<commit_before>package cmd

import (
	octopusdeploy_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/octopusdeploy"

	"github.com/GoogleCloudPlatform/terraformer/terraform_utils"
	"github.com/spf13/cobra"
)

func newCmdOctopusDeployImporter(options ImportOptions) *cobra.Command {
	var server, apiKey string
	cmd := &cobra.Command{
		Use:   "octopusdeploy",
		Short: "Import current state to Terraform configuration from Octopus Deploy",
		Long:  "Import current state to Terraform configuration from Octopus Deploy",
		RunE: func(cmd *cobra.Command, args []string) error {
			provider := newOctopusDeployProvider()
			err := Import(provider, options, []string{server, apiKey})
			if err != nil {
				return err
			}
			return nil
		},
	}

	cmd.AddCommand(listCmd(newOctopusDeployProvider()))
	baseProviderFlags(cmd.PersistentFlags(), &options, "tagset", "tagset")
	cmd.PersistentFlags().StringVar(&server, "server", "", "Octopus Server's API endpoint or env param OCTOPUS_CLI_SERVER")
	cmd.PersistentFlags().StringVar(&apiKey, "apiKey", "", "Octopus API key or env param OCTOPUS_CLI_API_KEY")
	return cmd
}

func newOctopusDeployProvider() terraform_utils.ProviderGenerator {
	return &octopusdeploy_terraforming.OctopusDeployProvider{}
}
<commit_msg>Keep CLI arguments lowercase<commit_after>package cmd

import (
	octopusdeploy_terraforming "github.com/GoogleCloudPlatform/terraformer/providers/octopusdeploy"

	"github.com/GoogleCloudPlatform/terraformer/terraform_utils"
	"github.com/spf13/cobra"
)

func newCmdOctopusDeployImporter(options ImportOptions) *cobra.Command {
	var server, apiKey string
	cmd := &cobra.Command{
		Use:   "octopusdeploy",
		Short: "Import current state to Terraform configuration from Octopus Deploy",
		Long:  "Import current state to Terraform configuration from Octopus Deploy",
		RunE: func(cmd *cobra.Command, args []string) error {
			provider := newOctopusDeployProvider()
			err := Import(provider, options, []string{server, apiKey})
			if err != nil {
				return err
			}
			return nil
		},
	}

	cmd.AddCommand(listCmd(newOctopusDeployProvider()))
	baseProviderFlags(cmd.PersistentFlags(), &options, "tagset", "tagset")
	cmd.PersistentFlags().StringVar(&server, "server", "", "Octopus Server's API endpoint or env param OCTOPUS_CLI_SERVER")
	cmd.PersistentFlags().StringVar(&apiKey, "apikey", "", "Octopus API key or env param OCTOPUS_CLI_API_KEY")
	return cmd
}

func newOctopusDeployProvider() terraform_utils.ProviderGenerator {
	return &octopusdeploy_terraforming.OctopusDeployProvider{}
}
<|endoftext|>


<commit_before>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	whhttp "github.com/slok/kubewebhook/pkg/http"
	"github.com/slok/kubewebhook/pkg/log"
	"github.com/slok/kubewebhook/pkg/webhook/mutating"
	"github.com/spf13/viper"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

type vaultConfig struct {
	addr       string
	role       string
	path       string
	skipVerify string
	useAgent   bool
}

var vaultAgentConfig = `
pid_file = "./pidfile"
exit_after_auth = true

auto_auth {
	method "kubernetes" {
		mount_path = "%s"
		config = {
			role = "%s"
		}
	}

	sink "file" {
		config = {
			path = "/vault/token"
		}
	}
}`

func getInitContainers(vaultConfig vaultConfig) []corev1.Container {
	containers := []corev1.Container{}

	if vaultConfig.useAgent {
		containers = append(containers, corev1.Container{
			Name:            "vault-agent",
			Image:           "banzaicloud/vault-secrets-init:latest",
			ImagePullPolicy: corev1.PullIfNotPresent,
			Command:         []string{"vault", "agent", "-config=/vault-agent/config.hcl"},
			Env: []corev1.EnvVar{
				{
					Name:  "VAULT_ADDR",
					Value: vaultConfig.addr,
				},
				{
					Name:  "VAULT_SKIP_VERIFY",
					Value: vaultConfig.skipVerify,
				},
			},
			VolumeMounts: []corev1.VolumeMount{
				{
					Name:      "vault-agent-config",
					MountPath: "/vault-agent/",
				},
				{
					Name:      "vault-env",
					MountPath: "/vault/",
				},
			},
		})
	}

	containers = append(containers, corev1.Container{
		Name:            "copy-vault-env",
		Image:           "banzaicloud/vault-env:latest",
		ImagePullPolicy: corev1.PullIfNotPresent,
		Command:         []string{"sh", "-c", "cp /usr/local/bin/vault-env /vault/"},
		VolumeMounts: []corev1.VolumeMount{
			{
				Name:      "vault-env",
				MountPath: "/vault/",
			},
		},
	})

	return containers
}

func getVolumes(name string, vaultConfig vaultConfig) []corev1.Volume {
	volumes := []corev1.Volume{
		{
			Name: "vault-env",
			VolumeSource: corev1.VolumeSource{
				EmptyDir: &corev1.EmptyDirVolumeSource{
					Medium: corev1.StorageMediumMemory,
				},
			},
		},
	}

	if vaultConfig.useAgent {
		volumes = append(volumes, corev1.Volume{
			Name: "vault-agent-config",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					LocalObjectReference: corev1.LocalObjectReference{
						Name: name + "-vault-agent-config",
					},
				},
			},
		})
	}

	return volumes
}

func vaultSecretsMutator(_ context.Context, obj metav1.Object) (bool, error) {
	var podSpec *corev1.PodSpec

	switch v := obj.(type) {
	case *appsv1.Deployment:
		podSpec = &v.Spec.Template.Spec
	case *appsv1.ReplicaSet:
		podSpec = &v.Spec.Template.Spec
	case *appsv1.StatefulSet:
		podSpec = &v.Spec.Template.Spec
	default:
		return false, nil
	}

	annotations := obj.GetAnnotations()
	if _, ok := annotations["vault.security.banzaicloud.io/mutated"]; ok {
		return false, nil
	}
	if annotations == nil {
		annotations = map[string]string{}
		obj.SetAnnotations(annotations)
	}
	annotations["vault.security.banzaicloud.io/mutated"] = "true"

	vaultConfig := parseVaultConfig(obj)

	return false, transformVaultEnvContainers(obj, podSpec, vaultConfig)
}

func parseVaultConfig(obj metav1.Object) vaultConfig {
	var vaultConfig vaultConfig
	annotations := obj.GetAnnotations()
	vaultConfig.addr = annotations["vault.security.banzaicloud.io/vault-addr"]
	vaultConfig.role = annotations["vault.security.banzaicloud.io/vault-role"]
	if vaultConfig.role == "" {
		vaultConfig.role = "default"
	}
	vaultConfig.path = annotations["vault.security.banzaicloud.io/vault-path"]
	if vaultConfig.path == "" {
		vaultConfig.path = "kubernetes"
	}
	vaultConfig.skipVerify = annotations["vault.security.banzaicloud.io/vault-skip-verify"]
	vaultConfig.useAgent, _ = strconv.ParseBool(annotations["vault.security.banzaicloud.io/vault-agent"])
	return vaultConfig
}

func getConfigMapForVaultAgent(obj metav1.Object, vaultConfig vaultConfig) *corev1.ConfigMap {
	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name: obj.GetName() + "-vault-agent-config",
			// OwnerReferences: []metav1.OwnerReference{
			// 	{
			// 		Name: obj.GetName(),
			// 		// UID:  obj.GetUID(),
			// 	},
			// },
		},
		Data: map[string]string{
			"config.hcl": fmt.Sprintf(vaultAgentConfig, vaultConfig.path, vaultConfig.role),
		},
	}
}

func transformVaultEnvContainers(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vaultConfig) error {

	kubeConfig, err := rest.InClusterConfig()
	if err != nil {
		return err
	}

	clientset, err := kubernetes.NewForConfig(kubeConfig)
	if err != nil {
		return err
	}

	mutated := false
	for i, container := range podSpec.Containers {
		var envVars []corev1.EnvVar
		for _, env := range container.Env {
			if strings.HasPrefix(env.Value, "vault:") {
				envVars = append(envVars, env)
			}
		}
		if len(envVars) == 0 {
			continue
		}

		mutated = true

		args := append(container.Command, container.Args...)

		container.Command = []string{"/vault/vault-env"}
		container.Args = args

		container.VolumeMounts = append(container.VolumeMounts, []corev1.VolumeMount{
			{
				Name:      "vault-env",
				MountPath: "/vault/",
			},
		}...)

		container.Env = append(container.Env, []corev1.EnvVar{
			{
				Name:  "VAULT_ADDR",
				Value: vaultConfig.addr,
			},
			{
				Name:  "VAULT_SKIP_VERIFY",
				Value: vaultConfig.skipVerify,
			},
			{
				Name:  "VAULT_PATH",
				Value: vaultConfig.path,
			},
			{
				Name:  "VAULT_ROLE",
				Value: vaultConfig.role,
			},
		}...)

		if vaultConfig.useAgent {
			container.Env = append(container.Env, corev1.EnvVar{
				Name:  "VAULT_TOKEN_FILE",
				Value: "/vault/token",
			})
		}

		podSpec.Containers[i] = container
	}

	if mutated {

		if vaultConfig.useAgent {

			configMap := getConfigMapForVaultAgent(obj, vaultConfig)

			_, err := clientset.CoreV1().ConfigMaps(obj.GetNamespace()).Create(configMap)
			if err != nil {
				if errors.IsAlreadyExists(err) {
					_, err = clientset.CoreV1().ConfigMaps(obj.GetNamespace()).Update(configMap)
					if err != nil {
						return err
					}
				} else {
					return err
				}
			}
		}

		podSpec.InitContainers = append(podSpec.InitContainers, getInitContainers(vaultConfig)...)
		podSpec.Volumes = append(podSpec.Volumes, getVolumes(obj.GetName(), vaultConfig)...)
	}

	return nil
}

func initConfig() {
	viper.AutomaticEnv()
}

func handlerFor(config mutating.WebhookConfig, mutator mutating.MutatorFunc, logger log.Logger) http.Handler {
	webhook, err := mutating.NewWebhook(config, mutator, nil, nil, logger)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating webhook: %s", err)
		os.Exit(1)
	}

	handler, err := whhttp.HandlerFor(webhook)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating webhook: %s", err)
		os.Exit(1)
	}

	return handler
}

func main() {

	initConfig()

	logger := &log.Std{Debug: true}

	mutator := mutating.MutatorFunc(vaultSecretsMutator)

	handlerDeployment := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.Deployment{}}, mutator, logger)
	handlerReplicaSet := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.ReplicaSet{}}, mutator, logger)
	handlerStatefulSet := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.StatefulSet{}}, mutator, logger)

	mux := http.NewServeMux()
	mux.Handle("/deployments", handlerDeployment)
	mux.Handle("/replicasets", handlerReplicaSet)
	mux.Handle("/statefulsets", handlerStatefulSet)

	logger.Infof("Listening on :443")
	err := http.ListenAndServeTLS(":443", viper.GetString("tls_cert_file"), viper.GetString("tls_private_key_file"), mux)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error serving webhook: %s", err)
		os.Exit(1)
	}
}
<commit_msg>webhook: support mutating initContainers<commit_after>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	whhttp "github.com/slok/kubewebhook/pkg/http"
	"github.com/slok/kubewebhook/pkg/log"
	"github.com/slok/kubewebhook/pkg/webhook/mutating"
	"github.com/spf13/viper"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

type vaultConfig struct {
	addr       string
	role       string
	path       string
	skipVerify string
	useAgent   bool
}

var vaultAgentConfig = `
pid_file = "./pidfile"
exit_after_auth = true

auto_auth {
	method "kubernetes" {
		mount_path = "%s"
		config = {
			role = "%s"
		}
	}

	sink "file" {
		config = {
			path = "/vault/token"
		}
	}
}`

func getInitContainers(vaultConfig vaultConfig) []corev1.Container {
	containers := []corev1.Container{}

	if vaultConfig.useAgent {
		containers = append(containers, corev1.Container{
			Name:            "vault-agent",
			Image:           "banzaicloud/vault-secrets-init:latest",
			ImagePullPolicy: corev1.PullIfNotPresent,
			Command:         []string{"vault", "agent", "-config=/vault-agent/config.hcl"},
			Env: []corev1.EnvVar{
				{
					Name:  "VAULT_ADDR",
					Value: vaultConfig.addr,
				},
				{
					Name:  "VAULT_SKIP_VERIFY",
					Value: vaultConfig.skipVerify,
				},
			},
			VolumeMounts: []corev1.VolumeMount{
				{
					Name:      "vault-agent-config",
					MountPath: "/vault-agent/",
				},
				{
					Name:      "vault-env",
					MountPath: "/vault/",
				},
			},
		})
	}

	containers = append(containers, corev1.Container{
		Name:            "copy-vault-env",
		Image:           "banzaicloud/vault-env:latest",
		ImagePullPolicy: corev1.PullIfNotPresent,
		Command:         []string{"sh", "-c", "cp /usr/local/bin/vault-env /vault/"},
		VolumeMounts: []corev1.VolumeMount{
			{
				Name:      "vault-env",
				MountPath: "/vault/",
			},
		},
	})

	return containers
}

func getVolumes(name string, vaultConfig vaultConfig) []corev1.Volume {
	volumes := []corev1.Volume{
		{
			Name: "vault-env",
			VolumeSource: corev1.VolumeSource{
				EmptyDir: &corev1.EmptyDirVolumeSource{
					Medium: corev1.StorageMediumMemory,
				},
			},
		},
	}

	if vaultConfig.useAgent {
		volumes = append(volumes, corev1.Volume{
			Name: "vault-agent-config",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					LocalObjectReference: corev1.LocalObjectReference{
						Name: name + "-vault-agent-config",
					},
				},
			},
		})
	}

	return volumes
}

func vaultSecretsMutator(_ context.Context, obj metav1.Object) (bool, error) {
	var podSpec *corev1.PodSpec

	switch v := obj.(type) {
	case *appsv1.Deployment:
		podSpec = &v.Spec.Template.Spec
	case *appsv1.ReplicaSet:
		podSpec = &v.Spec.Template.Spec
	case *appsv1.StatefulSet:
		podSpec = &v.Spec.Template.Spec
	default:
		return false, nil
	}

	annotations := obj.GetAnnotations()
	if _, ok := annotations["vault.security.banzaicloud.io/mutated"]; ok {
		return false, nil
	}
	if annotations == nil {
		annotations = map[string]string{}
		obj.SetAnnotations(annotations)
	}
	annotations["vault.security.banzaicloud.io/mutated"] = "true"

	vaultConfig := parseVaultConfig(obj)

	return false, mutatePodSpec(obj, podSpec, vaultConfig)
}

func parseVaultConfig(obj metav1.Object) vaultConfig {
	var vaultConfig vaultConfig
	annotations := obj.GetAnnotations()
	vaultConfig.addr = annotations["vault.security.banzaicloud.io/vault-addr"]
	vaultConfig.role = annotations["vault.security.banzaicloud.io/vault-role"]
	if vaultConfig.role == "" {
		vaultConfig.role = "default"
	}
	vaultConfig.path = annotations["vault.security.banzaicloud.io/vault-path"]
	if vaultConfig.path == "" {
		vaultConfig.path = "kubernetes"
	}
	vaultConfig.skipVerify = annotations["vault.security.banzaicloud.io/vault-skip-verify"]
	vaultConfig.useAgent, _ = strconv.ParseBool(annotations["vault.security.banzaicloud.io/vault-agent"])
	return vaultConfig
}

func getConfigMapForVaultAgent(obj metav1.Object, vaultConfig vaultConfig) *corev1.ConfigMap {
	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name: obj.GetName() + "-vault-agent-config",
			// OwnerReferences: []metav1.OwnerReference{
			// 	{
			// 		Name: obj.GetName(),
			// 		// UID:  obj.GetUID(),
			// 	},
			// },
		},
		Data: map[string]string{
			"config.hcl": fmt.Sprintf(vaultAgentConfig, vaultConfig.path, vaultConfig.role),
		},
	}
}

func mutateContainers(containers []corev1.Container, vaultConfig vaultConfig) bool {
	mutated := false
	for i, container := range containers {
		var envVars []corev1.EnvVar
		for _, env := range container.Env {
			if strings.HasPrefix(env.Value, "vault:") {
				envVars = append(envVars, env)
			}
		}
		if len(envVars) == 0 {
			continue
		}

		mutated = true

		args := append(container.Command, container.Args...)

		container.Command = []string{"/vault/vault-env"}
		container.Args = args

		container.VolumeMounts = append(container.VolumeMounts, []corev1.VolumeMount{
			{
				Name:      "vault-env",
				MountPath: "/vault/",
			},
		}...)

		container.Env = append(container.Env, []corev1.EnvVar{
			{
				Name:  "VAULT_ADDR",
				Value: vaultConfig.addr,
			},
			{
				Name:  "VAULT_SKIP_VERIFY",
				Value: vaultConfig.skipVerify,
			},
			{
				Name:  "VAULT_PATH",
				Value: vaultConfig.path,
			},
			{
				Name:  "VAULT_ROLE",
				Value: vaultConfig.role,
			},
		}...)

		if vaultConfig.useAgent {
			container.Env = append(container.Env, corev1.EnvVar{
				Name:  "VAULT_TOKEN_FILE",
				Value: "/vault/token",
			})
		}

		containers[i] = container
	}

	return mutated
}

func mutatePodSpec(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vaultConfig) error {

	kubeConfig, err := rest.InClusterConfig()
	if err != nil {
		return err
	}

	clientset, err := kubernetes.NewForConfig(kubeConfig)
	if err != nil {
		return err
	}

	initContainersMutated := mutateContainers(podSpec.InitContainers, vaultConfig)
	containersMutated := mutateContainers(podSpec.Containers, vaultConfig)

	if initContainersMutated || containersMutated {

		if vaultConfig.useAgent {

			configMap := getConfigMapForVaultAgent(obj, vaultConfig)

			_, err := clientset.CoreV1().ConfigMaps(obj.GetNamespace()).Create(configMap)
			if err != nil {
				if errors.IsAlreadyExists(err) {
					_, err = clientset.CoreV1().ConfigMaps(obj.GetNamespace()).Update(configMap)
					if err != nil {
						return err
					}
				} else {
					return err
				}
			}
		}

		podSpec.InitContainers = append(getInitContainers(vaultConfig), podSpec.InitContainers...)
		podSpec.Volumes = append(podSpec.Volumes, getVolumes(obj.GetName(), vaultConfig)...)
	}

	return nil
}

func initConfig() {
	viper.AutomaticEnv()
}

func handlerFor(config mutating.WebhookConfig, mutator mutating.MutatorFunc, logger log.Logger) http.Handler {
	webhook, err := mutating.NewWebhook(config, mutator, nil, nil, logger)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating webhook: %s", err)
		os.Exit(1)
	}

	handler, err := whhttp.HandlerFor(webhook)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating webhook: %s", err)
		os.Exit(1)
	}

	return handler
}

func main() {

	initConfig()

	logger := &log.Std{Debug: true}

	mutator := mutating.MutatorFunc(vaultSecretsMutator)

	handlerDeployment := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.Deployment{}}, mutator, logger)
	handlerReplicaSet := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.ReplicaSet{}}, mutator, logger)
	handlerStatefulSet := handlerFor(mutating.WebhookConfig{Name: "vault-secrets-deployment", Obj: &appsv1.StatefulSet{}}, mutator, logger)

	mux := http.NewServeMux()
	mux.Handle("/deployments", handlerDeployment)
	mux.Handle("/replicasets", handlerReplicaSet)
	mux.Handle("/statefulsets", handlerStatefulSet)

	logger.Infof("Listening on :443")
	err := http.ListenAndServeTLS(":443", viper.GetString("tls_cert_file"), viper.GetString("tls_private_key_file"), mux)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error serving webhook: %s", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Package mp provides accesstoken fetch functions for wechat mp dev
package mp

import (
	"strings"

	"github.com/bigwhite/gowechat/pb"
)

const (
	accessTokenFetchURL = "https://api.weixin.qq.com/cgi-bin/token"
)

// FetchAccessToken could be used to fetch access token for wechat qy dev.
func FetchAccessToken(appID, appSecret string) (string, float64, error) {
	requestLine := strings.Join([]string{accessTokenFetchURL,
		"?grant_type=client_credential&appid=",
		appID,
		"&secret=",
		appSecret}, "")

	return pb.FetchAccessToken(requestLine)
}
<commit_msg>add FetchWebAuthInfo for mp<commit_after>// Package mp provides accesstoken fetch functions for wechat mp dev
package mp

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/bigwhite/gowechat/pb"
)

const (
	accessTokenFetchURL    = "https://api.weixin.qq.com/cgi-bin/token"
	webAccessTokenFetchUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"
)

type WebAccessTokenResponse struct {
	AccessToken  string  `json:"access_token"`
	ExpiresIn    float64 `json:"expires_in"`
	RefreshToken string  `json:"refresh_token"`
	OpenID       string  `json:"openid"`
	Scope        string  `json:"scope"`
}

// FetchAccessToken could be used to fetch access token for wechat qy dev.
func FetchAccessToken(appID, appSecret string) (string, float64, error) {
	requestLine := strings.Join([]string{accessTokenFetchURL,
		"?grant_type=client_credential&appid=",
		appID,
		"&secret=",
		appSecret}, "")

	return pb.FetchAccessToken(requestLine)
}

// url:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
func FetchWebAuthInfo(appID, appSecret, code string) (*WebAccessTokenResponse, error) {
	requestLine := strings.Join([]string{webAccessTokenFetchUrl,
		"?appid=", appID, "&secret=", appSecret, "&code=", code,
		"&grant_type=authorization_code"}, "")

	resp, err := http.Get(requestLine)
	if err != nil || resp.StatusCode != http.StatusOK {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	//Json Decoding
	if bytes.Contains(body, []byte("access_token")) {
		atr := WebAccessTokenResponse{}
		err = json.Unmarshal(body, &atr)
		if err != nil {
			return nil, err
		}
		return &atr, nil
	} else {
		fmt.Println("return err")
		ater := pb.AccessTokenErrorResponse{}
		err = json.Unmarshal(body, &ater)
		if err != nil {
			return nil, err
		}
		return nil, fmt.Errorf("%s", ater.Errmsg)
	}
}
<|endoftext|>


<commit_before>package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		c, ok := <-v.commandChan

		if !ok {
			C.libvlc_media_player_release(i.player)
			i.player = nil
			C.libvlc_release(i.instance)
			i.instance = nil
			// channel is closed when player must quit

			close(i.eventChan)
			return
		}

		c(i)
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		v.checkError(C.libvlc_media_player_play(i.player))

		if position != 0 {
			C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
		}
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<commit_msg>bugfix: sometimes, player would be stuck in 'buffering' state<commit_after>package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {
		i.isPlaying = false
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		c, ok := <-v.commandChan

		if !ok {
			C.libvlc_media_player_release(i.player)
			i.player = nil
			C.libvlc_release(i.instance)
			i.instance = nil
			// channel is closed when player must quit

			close(i.eventChan)
			return
		}

		c(i)
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		v.checkError(C.libvlc_media_player_play(i.player))

		if position != 0 {
			C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
		}
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<|endoftext|>


<commit_before>package cdebug

import "os"
import "path/filepath"
import "strings"

var logDir string = ""
var w *os.File = nil

func prints(args []string) {
	if logDir == "" {
		logDir = filepath.Join(filepath.ToSlash(os.TempDir()), "DEBUG")
		fi, ok := os.Stat(logDir)
		if ok == nil && fi.IsDir() {
			fname := filepath.Base(filepath.ToSlash(os.Args[0]))
			lastPeriod := strings.LastIndex(fname, ".")
			if lastPeriod >= 0 {
				fname = fname[0:lastPeriod]
			}
			fullPath := filepath.Join(logDir, fname+".log")
			var err error
			w, err = os.OpenFile(filepath.ToSlash(fullPath), os.O_CREATE, 0666)
			if err != nil {
				w = nil
			}
		}
	}
	if w != nil {
		w.WriteString( strings.Join(args," ") )
	}
}

func Print(args ...string) {
	prints(args)
	if w != nil {
		w.Sync()
	}
}

func Println(args ...string) {
	prints(args)
	if w != nil {
		w.WriteString("\n")
		w.Sync()
	}
}
<commit_msg>go fmt for cdebug.go<commit_after>package cdebug

import "os"
import "path/filepath"
import "strings"

var logDir string = ""
var w *os.File = nil

func prints(args []string) {
	if logDir == "" {
		logDir = filepath.Join(filepath.ToSlash(os.TempDir()), "DEBUG")
		fi, ok := os.Stat(logDir)
		if ok == nil && fi.IsDir() {
			fname := filepath.Base(filepath.ToSlash(os.Args[0]))
			lastPeriod := strings.LastIndex(fname, ".")
			if lastPeriod >= 0 {
				fname = fname[0:lastPeriod]
			}
			fullPath := filepath.Join(logDir, fname+".log")
			var err error
			w, err = os.OpenFile(filepath.ToSlash(fullPath), os.O_CREATE, 0666)
			if err != nil {
				w = nil
			}
		}
	}
	if w != nil {
		w.WriteString(strings.Join(args, " "))
	}
}

func Print(args ...string) {
	prints(args)
	if w != nil {
		w.Sync()
	}
}

func Println(args ...string) {
	prints(args)
	if w != nil {
		w.WriteString("\n")
		w.Sync()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"log"
	"net/http"
	"net/http/httputil"

	"fmt"

	"github.com/Sirupsen/logrus"
	internalHandlers "github.com/alexellis/faas/gateway/handlers"
	"github.com/alexellis/faas/gateway/metrics"
	"github.com/alexellis/faas/gateway/types"
	"github.com/docker/docker/client"

	"github.com/gorilla/mux"
)

type handlerSet struct {
	Proxy          http.HandlerFunc
	DeployFunction http.HandlerFunc
	DeleteFunction http.HandlerFunc
	ListFunctions  http.HandlerFunc
	Alert          http.HandlerFunc
	RoutelessProxy http.HandlerFunc
}

func main() {
	logger := logrus.Logger{}
	logrus.SetFormatter(&logrus.TextFormatter{})

	osEnv := types.OsEnv{}
	readConfig := types.ReadConfig{}
	config := readConfig.Read(osEnv)

	log.Printf("HTTP Read Timeout: %s", config.ReadTimeout)
	log.Printf("HTTP Write Timeout: %s", config.WriteTimeout)

	var dockerClient *client.Client

	if config.UseExternalProvider() {
		log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
	} else {
		var err error
		dockerClient, err = client.NewEnvClient()
		if err != nil {
			log.Fatal("Error with Docker client.")
		}
		dockerVersion, err := dockerClient.ServerVersion(context.Background())
		if err != nil {
			log.Fatal("Error with Docker server.\n", err)
		}
		log.Printf("Docker API version: %s, %s\n", dockerVersion.APIVersion, dockerVersion.Version)
	}

	metricsOptions := metrics.BuildMetricsOptions()
	metrics.RegisterMetrics(metricsOptions)

	var faasHandlers handlerSet

	if config.UseExternalProvider() {

		reverseProxy := httputil.NewSingleHostReverseProxy(config.FunctionsProviderURL)

		faasHandlers.Proxy = handler(reverseProxy)
		faasHandlers.RoutelessProxy = handler(reverseProxy)
		faasHandlers.Alert = handler(reverseProxy)
		faasHandlers.ListFunctions = handler(reverseProxy)
		faasHandlers.DeployFunction = handler(reverseProxy)
		faasHandlers.DeleteFunction = handler(reverseProxy)

	} else {
		faasHandlers.Proxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
		faasHandlers.RoutelessProxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
		faasHandlers.Alert = internalHandlers.MakeAlertHandler(dockerClient)
		faasHandlers.ListFunctions = internalHandlers.MakeFunctionReader(metricsOptions, dockerClient)
		faasHandlers.DeployFunction = internalHandlers.MakeNewFunctionHandler(metricsOptions, dockerClient)
		faasHandlers.DeleteFunction = internalHandlers.MakeDeleteFunctionHandler(metricsOptions, dockerClient)

		// This could exist in a separate process - records the replicas of each swarm service.
		functionLabel := "function"
		metrics.AttachSwarmWatcher(dockerClient, metricsOptions, functionLabel)
	}

	r := mux.NewRouter()

	// r.StrictSlash(false)	// This didn't work, so register routes twice.
	r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", faasHandlers.Proxy)
	r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/", faasHandlers.Proxy)

	r.HandleFunc("/system/alert", faasHandlers.Alert)
	r.HandleFunc("/system/functions", faasHandlers.ListFunctions).Methods("GET")
	r.HandleFunc("/system/functions", faasHandlers.DeployFunction).Methods("POST")
	r.HandleFunc("/system/functions", faasHandlers.DeleteFunction).Methods("DELETE")

	fs := http.FileServer(http.Dir("./assets/"))
	r.PathPrefix("/ui/").Handler(http.StripPrefix("/ui", fs)).Methods("GET")

	r.HandleFunc("/", faasHandlers.RoutelessProxy).Methods("POST")

	metricsHandler := metrics.PrometheusHandler()
	r.Handle("/metrics", metricsHandler)
	r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods("GET")

	tcpPort := 8080

	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", tcpPort),
		ReadTimeout:    config.ReadTimeout,
		WriteTimeout:   config.WriteTimeout,
		MaxHeaderBytes: http.DefaultMaxHeaderBytes, // 1MB - can be overridden by setting Server.MaxHeaderBytes.
		Handler:        r,
	}

	log.Fatal(s.ListenAndServe())
}

func handler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Forwarding [%s] to %s", r.Method, r.URL.String())
		p.ServeHTTP(w, r)
	}
}
<commit_msg>Start logging metrics<commit_after>package main

import (
	"context"
	"log"
	"net/http"
	"net/http/httputil"
	"strconv"
	"strings"
	"time"

	"fmt"

	"github.com/Sirupsen/logrus"
	internalHandlers "github.com/alexellis/faas/gateway/handlers"
	"github.com/alexellis/faas/gateway/metrics"
	"github.com/alexellis/faas/gateway/types"
	"github.com/docker/docker/client"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/gorilla/mux"
)

type handlerSet struct {
	Proxy          http.HandlerFunc
	DeployFunction http.HandlerFunc
	DeleteFunction http.HandlerFunc
	ListFunctions  http.HandlerFunc
	Alert          http.HandlerFunc
	RoutelessProxy http.HandlerFunc
}

func main() {
	logger := logrus.Logger{}
	logrus.SetFormatter(&logrus.TextFormatter{})

	osEnv := types.OsEnv{}
	readConfig := types.ReadConfig{}
	config := readConfig.Read(osEnv)

	log.Printf("HTTP Read Timeout: %s", config.ReadTimeout)
	log.Printf("HTTP Write Timeout: %s", config.WriteTimeout)

	var dockerClient *client.Client

	if config.UseExternalProvider() {
		log.Printf("Binding to external function provider: %s", config.FunctionsProviderURL)
	} else {
		var err error
		dockerClient, err = client.NewEnvClient()
		if err != nil {
			log.Fatal("Error with Docker client.")
		}
		dockerVersion, err := dockerClient.ServerVersion(context.Background())
		if err != nil {
			log.Fatal("Error with Docker server.\n", err)
		}
		log.Printf("Docker API version: %s, %s\n", dockerVersion.APIVersion, dockerVersion.Version)
	}

	metricsOptions := metrics.BuildMetricsOptions()
	metrics.RegisterMetrics(metricsOptions)

	var faasHandlers handlerSet

	if config.UseExternalProvider() {

		reverseProxy := httputil.NewSingleHostReverseProxy(config.FunctionsProviderURL)

		faasHandlers.Proxy = makeHandler(reverseProxy, &metricsOptions)
		faasHandlers.RoutelessProxy = makeHandler(reverseProxy, &metricsOptions)
		faasHandlers.Alert = makeHandler(reverseProxy, &metricsOptions)
		faasHandlers.ListFunctions = makeHandler(reverseProxy, &metricsOptions)
		faasHandlers.DeployFunction = makeHandler(reverseProxy, &metricsOptions)
		faasHandlers.DeleteFunction = makeHandler(reverseProxy, &metricsOptions)

	} else {
		faasHandlers.Proxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
		faasHandlers.RoutelessProxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
		faasHandlers.Alert = internalHandlers.MakeAlertHandler(dockerClient)
		faasHandlers.ListFunctions = internalHandlers.MakeFunctionReader(metricsOptions, dockerClient)
		faasHandlers.DeployFunction = internalHandlers.MakeNewFunctionHandler(metricsOptions, dockerClient)
		faasHandlers.DeleteFunction = internalHandlers.MakeDeleteFunctionHandler(metricsOptions, dockerClient)

		// This could exist in a separate process - records the replicas of each swarm service.
		functionLabel := "function"
		metrics.AttachSwarmWatcher(dockerClient, metricsOptions, functionLabel)
	}

	r := mux.NewRouter()

	// r.StrictSlash(false)	// This didn't work, so register routes twice.
	r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", faasHandlers.Proxy)
	r.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/", faasHandlers.Proxy)

	r.HandleFunc("/system/alert", faasHandlers.Alert)
	r.HandleFunc("/system/functions", faasHandlers.ListFunctions).Methods("GET")
	r.HandleFunc("/system/functions", faasHandlers.DeployFunction).Methods("POST")
	r.HandleFunc("/system/functions", faasHandlers.DeleteFunction).Methods("DELETE")

	fs := http.FileServer(http.Dir("./assets/"))
	r.PathPrefix("/ui/").Handler(http.StripPrefix("/ui", fs)).Methods("GET")

	r.HandleFunc("/", faasHandlers.RoutelessProxy).Methods("POST")

	metricsHandler := metrics.PrometheusHandler()
	r.Handle("/metrics", metricsHandler)
	r.Handle("/", http.RedirectHandler("/ui/", http.StatusMovedPermanently)).Methods("GET")

	tcpPort := 8080

	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", tcpPort),
		ReadTimeout:    config.ReadTimeout,
		WriteTimeout:   config.WriteTimeout,
		MaxHeaderBytes: http.DefaultMaxHeaderBytes, // 1MB - can be overridden by setting Server.MaxHeaderBytes.
		Handler:        r,
	}

	log.Fatal(s.ListenAndServe())
}

// WriteAdapter adapts a ResponseWriter
type WriteAdapter struct {
	Writer     http.ResponseWriter
	HttpResult *HttpResult
}
type HttpResult struct {
	HeaderCode int
}

//NewWriteAdapter create a new NewWriteAdapter
func NewWriteAdapter(w http.ResponseWriter) WriteAdapter {
	return WriteAdapter{Writer: w, HttpResult: &HttpResult{}}
}

//Header adapts Header
func (w WriteAdapter) Header() http.Header {
	return w.Writer.Header()
}

// Write adapts Write
func (w WriteAdapter) Write(data []byte) (int, error) {
	return w.Writer.Write(data)
}

// WriteHeader adapts WriteHeader
func (w WriteAdapter) WriteHeader(i int) {
	w.Writer.WriteHeader(i)
	w.HttpResult.HeaderCode = i
	fmt.Println("GetHeaderCode before", w.HttpResult.HeaderCode)
}

// GetHeaderCode result from WriteHeader
func (w *WriteAdapter) GetHeaderCode() int {
	return w.HttpResult.HeaderCode
}

func makeHandler(proxy *httputil.ReverseProxy, metrics *metrics.MetricOptions) http.HandlerFunc {
	// return func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		uri := r.URL.String()

		log.Printf("Forwarding [%s] to %s", r.Method, r.URL.String())
		start := time.Now()

		writeAdapter := NewWriteAdapter(w)
		proxy.ServeHTTP(writeAdapter, r)

		seconds := time.Since(start).Seconds()
		fmt.Printf("[%d] took %f seconds\n", writeAdapter.GetHeaderCode(), seconds)

		forward := "/function/"
		// fmt.Println(uri)
		if len(uri) > len(forward) && strings.Index(uri, forward) == 0 {
			fmt.Println("function=", uri[len(forward):])
			service := uri[len(forward):]
			metrics.GatewayFunctionsHistogram.WithLabelValues(service).Observe(seconds)
			code := writeAdapter.GetHeaderCode()
			metrics.GatewayFunctionInvocation.With(prometheus.Labels{"function_name": service, "code": strconv.Itoa(code)}).Inc()

		}

		// metricsOptions.
	}
	// }
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/weaveworks/flux/common/store"
	"github.com/weaveworks/flux/common/store/etcdstore"
	"github.com/weaveworks/flux/common/version"

	"github.com/gorilla/mux"
)

func main() {
	log.Println(version.Banner())
	prom := os.Getenv("PROMETHEUS_ADDRESS")
	if prom == "" {
		prom = "http://localhost:9090"
	}

	store, err := etcdstore.NewFromEnv()
	if err != nil {
		log.Fatal(err)
	}

	if err := store.Ping(); err != nil {
		log.Fatal(err)
	}

	log.Printf("Connected to backend\n")
	api := &api{store, prom}

	http.ListenAndServe("0.0.0.0:7070", api.router())
}

func handleResource(w http.ResponseWriter, r *http.Request) {
	file := r.URL.Path[1:]
	http.ServeFile(w, r, file)
}

func homePage(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "index.html")
}

//=== API handlers

type api struct {
	store   store.Store
	promURL string
}

func (api *api) router() http.Handler {
	router := mux.NewRouter()

	router.HandleFunc("/", homePage)
	router.HandleFunc("/index.html", homePage)
	router.PathPrefix("/assets/").HandlerFunc(handleResource)

	router.HandleFunc("/api/services", api.allServices)
	router.PathPrefix("/stats/").HandlerFunc(api.proxyStats)

	return router
}

// List all services, along with their instances and accompanying
// metadata.

func (api *api) allServices(w http.ResponseWriter, r *http.Request) {
	services, err := api.store.GetAllServices(store.QueryServiceOptions{WithInstances: true})
	if err != nil {
		http.Error(w, "Error getting services from store: "+err.Error(), 500)
	}
	json.NewEncoder(w).Encode(&services)
}

/* Proxy for prometheus, as a stop-gap */

func (api *api) proxyStats(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path[len("/stats"):] + "?" + r.URL.RawQuery
	log.Println(path)
	resp, err := http.Get(api.promURL + path)
	if err != nil {
		http.Error(w, "Error contacting prometheus server: "+err.Error(), 500)
		return
	}
	defer resp.Body.Close()
	for k, vs := range resp.Header {
		w.Header()[k] = vs
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}
<commit_msg>Log when flux-web fails to successfully forward request to prometheus<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/weaveworks/flux/common/store"
	"github.com/weaveworks/flux/common/store/etcdstore"
	"github.com/weaveworks/flux/common/version"

	"github.com/gorilla/mux"
)

func main() {
	log.Println(version.Banner())
	prom := os.Getenv("PROMETHEUS_ADDRESS")
	if prom == "" {
		prom = "http://localhost:9090"
	}

	store, err := etcdstore.NewFromEnv()
	if err != nil {
		log.Fatal(err)
	}

	if err := store.Ping(); err != nil {
		log.Fatal(err)
	}

	log.Printf("Connected to backend\n")
	api := &api{store, prom}

	http.ListenAndServe("0.0.0.0:7070", api.router())
}

func handleResource(w http.ResponseWriter, r *http.Request) {
	file := r.URL.Path[1:]
	http.ServeFile(w, r, file)
}

func homePage(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "index.html")
}

//=== API handlers

type api struct {
	store   store.Store
	promURL string
}

func (api *api) router() http.Handler {
	router := mux.NewRouter()

	router.HandleFunc("/", homePage)
	router.HandleFunc("/index.html", homePage)
	router.PathPrefix("/assets/").HandlerFunc(handleResource)

	router.HandleFunc("/api/services", api.allServices)
	router.PathPrefix("/stats/").HandlerFunc(api.proxyStats)

	return router
}

// List all services, along with their instances and accompanying
// metadata.

func (api *api) allServices(w http.ResponseWriter, r *http.Request) {
	services, err := api.store.GetAllServices(store.QueryServiceOptions{WithInstances: true})
	if err != nil {
		http.Error(w, "Error getting services from store: "+err.Error(), 500)
	}
	json.NewEncoder(w).Encode(&services)
}

/* Proxy for prometheus, as a stop-gap */

func (api *api) proxyStats(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path[len("/stats"):] + "?" + r.URL.RawQuery
	resp, err := http.Get(api.promURL + path)
	if err != nil {
		log.Printf("Error forwarding to prometheus at %s: %s", path, err)
		return
	}

	if resp.StatusCode != 200 {
		log.Printf("Request to prometheus at %d: %d response", path, resp.StatusCode)
	}

	defer resp.Body.Close()
	for k, vs := range resp.Header {
		w.Header()[k] = vs
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}
<|endoftext|>


<commit_before>package logics

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/qb0C80aE/clay/extensions"
	"github.com/qb0C80aE/clay/models"
	"net/url"
	"os"
	"sort"
	"strconv"
	"sync"
)

var commandMap map[int]*models.Command = map[int]*models.Command{}
var commandMapMutex = new(sync.Mutex)

const (
	commandStatusCreated  = "created"
	commandStatusRunning  = "running"
	commandStatusFinished = "finished"
)

type commandLogic struct {
	*BaseLogic
}

func newCommandLogic() *commandLogic {
	logic := &commandLogic{
		BaseLogic: NewBaseLogic(
			models.SharedCommandModel(),
		),
	}
	return logic
}

func (logic *commandLogic) GetSingle(db *gorm.DB, parameters gin.Params, _ url.Values, queryFields string) (interface{}, error) {

	id, _ := strconv.Atoi(parameters.ByName("id"))

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	command, exists := commandMap[id]

	if !exists {
		return nil, errors.New("record not found")
	}

	return command, nil

}

func (logic *commandLogic) GetMulti(db *gorm.DB, _ gin.Params, _ url.Values, queryFields string) (interface{}, error) {

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	keys := make([]int, 0, len(commandMap))
	for key := range commandMap {
		keys = append(keys, key)
	}

	sort.Ints(keys)

	commands := make([]*models.Command, len(commandMap))

	for i, key := range keys {
		commands[i] = commandMap[key]
	}

	return commands, nil

}

func (logic *commandLogic) Create(db *gorm.DB, _ gin.Params, _ url.Values, data interface{}) (interface{}, error) {

	command := data.(*models.Command)

	if len(command.WorkingDirectory) == 0 {
		var err error
		if command.WorkingDirectory, err = os.Getwd(); err != nil {
			return nil, err
		}
	}

	command.Status = commandStatusCreated

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	id := len(commandMap) + 1
	command.ID = id
	commandMap[id] = command

	return command, nil

}

func (logic *commandLogic) Delete(db *gorm.DB, parameters gin.Params, _ url.Values) error {

	id, _ := strconv.Atoi(parameters.ByName("id"))

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	command, exists := commandMap[id]

	if !exists {
		commandMapMutex.Unlock()
		return errors.New("record not found")
	}

	if command.Status == commandStatusRunning {
		return errors.New("command is running")
	}

	delete(commandMap, id)

	return nil
}

func (logic *commandLogic) Total(_ *gorm.DB, _ interface{}) (int, error) {
	return len(commandMap), nil
}

var uniqueCommandLogic = newCommandLogic()

// UniqueCommandLogic returns the unique command logic instance
func UniqueCommandLogic() extensions.Logic {
	return uniqueCommandLogic
}

func init() {
	extensions.RegisterLogic(models.SharedCommandModel(), UniqueCommandLogic())
}
<commit_msg>Fix statement warned by golint<commit_after>package logics

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/qb0C80aE/clay/extensions"
	"github.com/qb0C80aE/clay/models"
	"net/url"
	"os"
	"sort"
	"strconv"
	"sync"
)

var commandMap = map[int]*models.Command{}
var commandMapMutex = new(sync.Mutex)

const (
	commandStatusCreated  = "created"
	commandStatusRunning  = "running"
	commandStatusFinished = "finished"
)

type commandLogic struct {
	*BaseLogic
}

func newCommandLogic() *commandLogic {
	logic := &commandLogic{
		BaseLogic: NewBaseLogic(
			models.SharedCommandModel(),
		),
	}
	return logic
}

func (logic *commandLogic) GetSingle(db *gorm.DB, parameters gin.Params, _ url.Values, queryFields string) (interface{}, error) {

	id, _ := strconv.Atoi(parameters.ByName("id"))

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	command, exists := commandMap[id]

	if !exists {
		return nil, errors.New("record not found")
	}

	return command, nil

}

func (logic *commandLogic) GetMulti(db *gorm.DB, _ gin.Params, _ url.Values, queryFields string) (interface{}, error) {

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	keys := make([]int, 0, len(commandMap))
	for key := range commandMap {
		keys = append(keys, key)
	}

	sort.Ints(keys)

	commands := make([]*models.Command, len(commandMap))

	for i, key := range keys {
		commands[i] = commandMap[key]
	}

	return commands, nil

}

func (logic *commandLogic) Create(db *gorm.DB, _ gin.Params, _ url.Values, data interface{}) (interface{}, error) {

	command := data.(*models.Command)

	if len(command.WorkingDirectory) == 0 {
		var err error
		if command.WorkingDirectory, err = os.Getwd(); err != nil {
			return nil, err
		}
	}

	command.Status = commandStatusCreated

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	id := len(commandMap) + 1
	command.ID = id
	commandMap[id] = command

	return command, nil

}

func (logic *commandLogic) Delete(db *gorm.DB, parameters gin.Params, _ url.Values) error {

	id, _ := strconv.Atoi(parameters.ByName("id"))

	commandMapMutex.Lock()
	defer commandMapMutex.Unlock()

	command, exists := commandMap[id]

	if !exists {
		commandMapMutex.Unlock()
		return errors.New("record not found")
	}

	if command.Status == commandStatusRunning {
		return errors.New("command is running")
	}

	delete(commandMap, id)

	return nil
}

func (logic *commandLogic) Total(_ *gorm.DB, _ interface{}) (int, error) {
	return len(commandMap), nil
}

var uniqueCommandLogic = newCommandLogic()

// UniqueCommandLogic returns the unique command logic instance
func UniqueCommandLogic() extensions.Logic {
	return uniqueCommandLogic
}

func init() {
	extensions.RegisterLogic(models.SharedCommandModel(), UniqueCommandLogic())
}
<|endoftext|>


<commit_before>package login

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"
	"sync"

	"github.com/Bplotka/oidc"
)

const (
	codeParam  = "code"
	stateParam = "state"

	errParam     = "error"
	errDescParam = "error_description"
)

func rand128Bits() string {
	buff := make([]byte, 16) // 128 bit random ID.
	if _, err := io.ReadFull(rand.Reader, buff); err != nil {
		panic(err)
	}
	return strings.TrimRight(base64.URLEncoding.EncodeToString(buff), "=")
}

// open opens the specified URL in the default browser of the user.
func openBrowser(url string) error {
	var cmd string
	var args []string

	switch runtime.GOOS {
	case "windows":
		cmd = "cmd"
		args = []string{"/c", "start"}
	case "darwin":
		cmd = "open"
	default: // "linux", "freebsd", "openbsd", "netbsd"
		cmd = "xdg-open"
	}
	args = append(args, url)
	return exec.Command(cmd, args...).Start()
}

// callbackResponse contains return message from callback server including token or error.
type callbackResponse struct {
	token *oidc.Token
	err   error
}

// callbackRequest specifies values that are needed for expected callback handling.
type callbackRequest struct {
	ctx           context.Context
	expectedState string

	cfg    oidc.Config
	client *oidc.Client
}

// CallbackServer carries a callback handler for OIDC auth code flow.
// NOTE: This is not thread-safe in terms of multiple logins in the same time.
type CallbackServer struct {
	redirectURL string
	callbackCh  chan *callbackResponse

	// If empty, nothing is expected, so callback should immediately return err.
	callbackReqMu sync.Mutex
	callbackReq   *callbackRequest
}

// NewServer creates HTTP server with OIDC callback on the bindAddress an argument. BindAddress is the ultimately a redirectURL that all clients MUST register
// first on the OIDC server. It can (and is recommended) to point to localhost. Bind Address must include port. You can specify 0 if your
// OIDC provider support wildcard on port (almost all server does NOT).
func NewServer(bindAddress string) (srv *CallbackServer, closeSrv func(), err error) {
	bindURL, err := url.Parse(bindAddress)
	if err != nil {
		return nil, nil, fmt.Errorf("BindAddress is not in a form of URL. Err: %v", err)
	}

	listener, err := net.Listen("tcp", bindURL.Host)
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to Listen for tcp on: %s. Err: %v", bindURL.Host, err)
	}

	s := &CallbackServer{
		redirectURL: fmt.Sprintf("http://%s%s", listener.Addr().String(), bindURL.Path),
		callbackCh:  make(chan *callbackResponse),
	}
	mux := http.NewServeMux()
	mux.HandleFunc(bindURL.Path, s.callbackHandler)

	go func() {
		http.Serve(listener, mux)
	}()

	return s, func() {
		listener.Close()
		close(s.callbackCh)
	}, nil
}

// NewReuseServer creates HTTP server with OIDC callback registered on given HTTP mux. Server constructed in such way
// is not responsible for serving the callback. This is responsibility of the caller.
func NewReuseServer(pattern string, listenAddress string, mux *http.ServeMux) (*CallbackServer, error) {
	s := &CallbackServer{
		redirectURL: fmt.Sprintf("http://%s%s", listenAddress, pattern),
		callbackCh:  make(chan *callbackResponse),
	}
	mux.HandleFunc(pattern, s.callbackHandler)

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	go func() {
		<-quit
		close(s.callbackCh)
	}()
	return s, nil
}

// callbackHandler handles redirect from OIDC provider with either code or error parameters.
// If none callback is expected it will return error.
// In case of valid code with corresponded state it will perform token exchange with OIDC provider.
// Any message is propagated via Go channel if the callback was expected.
// NOTE: This is not thread-safe in terms of multiple logins in the same time.
func (s *CallbackServer) callbackHandler(w http.ResponseWriter, r *http.Request) {
	s.callbackReqMu.Lock()
	defer s.callbackReqMu.Unlock()

	if s.callbackReq == nil {
		w.WriteHeader(http.StatusPreconditionFailed)
		w.Write([]byte("Did not expect OIDC callback"))
		return
	}
	defer func() {
		s.callbackReq = nil
	}()

	err := r.ParseForm()
	if err != nil {
		err := fmt.Errorf("Failed to parse request form. Err: %v", err)
		s.errRespond(w, r, err)
		return
	}

	code, state, err := parseCallbackRequest(r.Form)
	if err != nil {
		s.errRespond(w, r, err)
		return
	}

	if state != s.callbackReq.expectedState {
		err := fmt.Errorf("Invalid state parameter. Got %s, expected: %s", state, s.callbackReq.expectedState)
		s.errRespond(w, r, err)
		return
	}

	ctx := mergeContexts(r.Context(), s.callbackReq.ctx)
	oidcToken, err := s.callbackReq.client.Exchange(ctx, s.callbackReq.cfg, code)
	if err != nil {
		s.errRespond(w, r, err)
		return
	}

	callbackResponse := &callbackResponse{
		token: oidcToken,
	}
	OKCallbackResponse(w, r)
	select {
	case <-s.callbackReq.ctx.Done():
	case s.callbackCh <- callbackResponse:
	}
	return
}

func parseCallbackRequest(form url.Values) (code string, state string, err error) {
	state = form.Get(stateParam)
	if state == "" {
		return "", "", errors.New("User session error. No state parameter.")
	}

	if errorCode := form.Get(errParam); errorCode != "" {
		// Got error from provider. Passing through.
		return "", "", fmt.Errorf("Got error from provider: %s Desc: %s", errorCode, form.Get(errDescParam))
	}

	code = form.Get(codeParam)
	if code == "" {
		return "", "", errors.New("Missing code token.")
	}

	return code, state, nil
}

// OKCallbackResponse is package wide function variable that returns HTTP response on successful OIDC `code` flow.
var OKCallbackResponse = func(w http.ResponseWriter, _ *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OIDC authentication flow is completed. You can close browser tab."))
}

// ErrCallbackResponse is package wide function variable that returns HTTP response on failed OIDC `code` flow.
// Note that, by default we don't want user to see anything wrong on browser side. All errors are propagated to command.
// If it is required otherwise, override this function.
var ErrCallbackResponse = func(w http.ResponseWriter, _ *http.Request, _ error) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OIDC authentication flow is completed. You can close browser tab."))
}

func (s *CallbackServer) errRespond(w http.ResponseWriter, r *http.Request, err error) {
	callbackResponse := &callbackResponse{
		err: err,
	}
	ErrCallbackResponse(w, r, err)

	select {
	case <-s.callbackReq.ctx.Done():
	case s.callbackCh <- callbackResponse:
	}
	return
}

func mergeContexts(originalCtx context.Context, oidcCtx context.Context) context.Context {
	if customClient := originalCtx.Value(oidc.HTTPClientCtxKey); customClient != nil {
		return originalCtx
	}
	return context.WithValue(originalCtx, oidc.HTTPClientCtxKey, oidcCtx.Value(oidc.HTTPClientCtxKey))
}

func (s *CallbackServer) ExpectCallback(callbackReq *callbackRequest) {
	s.callbackReqMu.Lock()
	defer s.callbackReqMu.Unlock()
	s.callbackReq = callbackReq
}

func (s *CallbackServer) Callback() <-chan *callbackResponse {
	return s.callbackCh
}

func (s *CallbackServer) RedirectURL() string {
	return s.redirectURL
}
<commit_msg>ReuseServer constructor does not return err.<commit_after>package login

import (
	"context"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"
	"sync"

	"github.com/Bplotka/oidc"
)

const (
	codeParam  = "code"
	stateParam = "state"

	errParam     = "error"
	errDescParam = "error_description"
)

func rand128Bits() string {
	buff := make([]byte, 16) // 128 bit random ID.
	if _, err := io.ReadFull(rand.Reader, buff); err != nil {
		panic(err)
	}
	return strings.TrimRight(base64.URLEncoding.EncodeToString(buff), "=")
}

// open opens the specified URL in the default browser of the user.
func openBrowser(url string) error {
	var cmd string
	var args []string

	switch runtime.GOOS {
	case "windows":
		cmd = "cmd"
		args = []string{"/c", "start"}
	case "darwin":
		cmd = "open"
	default: // "linux", "freebsd", "openbsd", "netbsd"
		cmd = "xdg-open"
	}
	args = append(args, url)
	return exec.Command(cmd, args...).Start()
}

// callbackResponse contains return message from callback server including token or error.
type callbackResponse struct {
	token *oidc.Token
	err   error
}

// callbackRequest specifies values that are needed for expected callback handling.
type callbackRequest struct {
	ctx           context.Context
	expectedState string

	cfg    oidc.Config
	client *oidc.Client
}

// CallbackServer carries a callback handler for OIDC auth code flow.
// NOTE: This is not thread-safe in terms of multiple logins in the same time.
type CallbackServer struct {
	redirectURL string
	callbackCh  chan *callbackResponse

	// If empty, nothing is expected, so callback should immediately return err.
	callbackReqMu sync.Mutex
	callbackReq   *callbackRequest
}

// NewServer creates HTTP server with OIDC callback on the bindAddress an argument. BindAddress is the ultimately a redirectURL that all clients MUST register
// first on the OIDC server. It can (and is recommended) to point to localhost. Bind Address must include port. You can specify 0 if your
// OIDC provider support wildcard on port (almost all server does NOT).
func NewServer(bindAddress string) (srv *CallbackServer, closeSrv func(), err error) {
	bindURL, err := url.Parse(bindAddress)
	if err != nil {
		return nil, nil, fmt.Errorf("BindAddress is not in a form of URL. Err: %v", err)
	}

	listener, err := net.Listen("tcp", bindURL.Host)
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to Listen for tcp on: %s. Err: %v", bindURL.Host, err)
	}

	s := &CallbackServer{
		redirectURL: fmt.Sprintf("http://%s%s", listener.Addr().String(), bindURL.Path),
		callbackCh:  make(chan *callbackResponse),
	}
	mux := http.NewServeMux()
	mux.HandleFunc(bindURL.Path, s.callbackHandler)

	go func() {
		http.Serve(listener, mux)
	}()

	return s, func() {
		listener.Close()
		close(s.callbackCh)
	}, nil
}

// NewReuseServer creates HTTP server with OIDC callback registered on given HTTP mux. Server constructed in such way
// is not responsible for serving the callback. This is responsibility of the caller.
func NewReuseServer(pattern string, listenAddress string, mux *http.ServeMux) *CallbackServer {
	s := &CallbackServer{
		redirectURL: fmt.Sprintf("http://%s%s", listenAddress, pattern),
		callbackCh:  make(chan *callbackResponse),
	}
	mux.HandleFunc(pattern, s.callbackHandler)

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	go func() {
		<-quit
		close(s.callbackCh)
	}()
	return s
}

// callbackHandler handles redirect from OIDC provider with either code or error parameters.
// If none callback is expected it will return error.
// In case of valid code with corresponded state it will perform token exchange with OIDC provider.
// Any message is propagated via Go channel if the callback was expected.
// NOTE: This is not thread-safe in terms of multiple logins in the same time.
func (s *CallbackServer) callbackHandler(w http.ResponseWriter, r *http.Request) {
	s.callbackReqMu.Lock()
	defer s.callbackReqMu.Unlock()

	if s.callbackReq == nil {
		w.WriteHeader(http.StatusPreconditionFailed)
		w.Write([]byte("Did not expect OIDC callback"))
		return
	}
	defer func() {
		s.callbackReq = nil
	}()

	err := r.ParseForm()
	if err != nil {
		err := fmt.Errorf("Failed to parse request form. Err: %v", err)
		s.errRespond(w, r, err)
		return
	}

	code, state, err := parseCallbackRequest(r.Form)
	if err != nil {
		s.errRespond(w, r, err)
		return
	}

	if state != s.callbackReq.expectedState {
		err := fmt.Errorf("Invalid state parameter. Got %s, expected: %s", state, s.callbackReq.expectedState)
		s.errRespond(w, r, err)
		return
	}

	ctx := mergeContexts(r.Context(), s.callbackReq.ctx)
	oidcToken, err := s.callbackReq.client.Exchange(ctx, s.callbackReq.cfg, code)
	if err != nil {
		s.errRespond(w, r, err)
		return
	}

	callbackResponse := &callbackResponse{
		token: oidcToken,
	}
	OKCallbackResponse(w, r)
	select {
	case <-s.callbackReq.ctx.Done():
	case s.callbackCh <- callbackResponse:
	}
	return
}

func parseCallbackRequest(form url.Values) (code string, state string, err error) {
	state = form.Get(stateParam)
	if state == "" {
		return "", "", errors.New("User session error. No state parameter.")
	}

	if errorCode := form.Get(errParam); errorCode != "" {
		// Got error from provider. Passing through.
		return "", "", fmt.Errorf("Got error from provider: %s Desc: %s", errorCode, form.Get(errDescParam))
	}

	code = form.Get(codeParam)
	if code == "" {
		return "", "", errors.New("Missing code token.")
	}

	return code, state, nil
}

// OKCallbackResponse is package wide function variable that returns HTTP response on successful OIDC `code` flow.
var OKCallbackResponse = func(w http.ResponseWriter, _ *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OIDC authentication flow is completed. You can close browser tab."))
}

// ErrCallbackResponse is package wide function variable that returns HTTP response on failed OIDC `code` flow.
// Note that, by default we don't want user to see anything wrong on browser side. All errors are propagated to command.
// If it is required otherwise, override this function.
var ErrCallbackResponse = func(w http.ResponseWriter, _ *http.Request, _ error) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OIDC authentication flow is completed. You can close browser tab."))
}

func (s *CallbackServer) errRespond(w http.ResponseWriter, r *http.Request, err error) {
	callbackResponse := &callbackResponse{
		err: err,
	}
	ErrCallbackResponse(w, r, err)

	select {
	case <-s.callbackReq.ctx.Done():
	case s.callbackCh <- callbackResponse:
	}
	return
}

func mergeContexts(originalCtx context.Context, oidcCtx context.Context) context.Context {
	if customClient := originalCtx.Value(oidc.HTTPClientCtxKey); customClient != nil {
		return originalCtx
	}
	return context.WithValue(originalCtx, oidc.HTTPClientCtxKey, oidcCtx.Value(oidc.HTTPClientCtxKey))
}

func (s *CallbackServer) ExpectCallback(callbackReq *callbackRequest) {
	s.callbackReqMu.Lock()
	defer s.callbackReqMu.Unlock()
	s.callbackReq = callbackReq
}

func (s *CallbackServer) Callback() <-chan *callbackResponse {
	return s.callbackCh
}

func (s *CallbackServer) RedirectURL() string {
	return s.redirectURL
}
<|endoftext|>


<commit_before>package v1alpha1

import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/knative/pkg/apis"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestTaskRunValidate(t *testing.T) {
	tests := []struct {
		name string
		task TaskRun
		want *apis.FieldError
	}{
		{
			name: "invalid taskspec",
			task: TaskRun{
				ObjectMeta: metav1.ObjectMeta{
					Name: "taskmetaname",
				},
			},
			want: apis.ErrMissingField("spec"),
		},
		{
			name: "invalid taskrun metadata",
			task: TaskRun{
				ObjectMeta: metav1.ObjectMeta{
					Name: "task.name",
				},
			},
			want: &apis.FieldError{
				Message: "Invalid resource name: special character . must not be present",
				Paths:   []string{"metadata.name"},
			},
		},
	}

	for _, ts := range tests {
		t.Run(ts.name, func(t *testing.T) {
			err := ts.task.Validate()
			if d := cmp.Diff(err.Error(), ts.want.Error()); d != "" {
				t.Errorf("Validate/%s (-want, +got) = %v", ts.name, d)
			}
		})
	}
}

func TestTaskRunSpecValidate(t *testing.T) {
	tests := []struct {
		name    string
		spec    *TaskRunSpec
		wantErr *apis.FieldError
	}{
		{
			name:    "invalid taskspec",
			spec:    &TaskRunSpec{},
			wantErr: apis.ErrMissingField("spec"),
		},
		{
			name: "invalid taskref",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: TaskTriggerTypePipelineRun,
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.taskref.name"),
		},
		{
			name: "invalid taskref",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.trigger.triggerref.type"),
		},
		{
			name: "valid task trigger run type",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: TaskTriggerTypePipelineRun,
					},
				},
			},
		},
		{
			name: "valid task inputs",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Params: []Param{{
						Name:  "name",
						Value: "value",
					}},
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
				},
			},
		},
		{
			name: "invalid task inputs",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}, {
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.Inputs.Resources.Name"),
		},
		{
			name: "invalid task input params",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
					Params: []Param{{
						Name:  "name",
						Value: "value",
					}, {
						Name:  "name",
						Value: "value",
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.inputs.params"),
		},
		{
			name: "invalid task output type",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Name: "resourceName",
						Type: "invalidtype",
					}},
				},
			},
			// TODO(shashwathi): wrong error msg
			wantErr: apis.ErrInvalidValue("invalidtype", "spec.Outputs.Resources.resourceName.Type"),
		},
		{
			name: "duplicate task output name",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Type: "git",
						Name: "resource1",
					}, {
						Type: "git",
						Name: "resource1",
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.Outputs.Resources.Name"),
		},
		{
			name: "valid task output",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Type: "git",
					}},
				},
			},
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Logs: ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.logs.Type"),
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.runs.Type"),
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Tests: &ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.tests.Type"),
		},
		{
			name: "invalid task type result name",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "",
						Type: ResultTargetTypeGCS,
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.results.runs.name"),
		},
		{
			name: "invalid task type result url",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "resultrunname",
						Type: ResultTargetTypeGCS,
						URL:  "",
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.results.runs.URL"),
		},
		{
			name: "valid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "testname",
						Type: ResultTargetTypeGCS,
						URL:  "http://github.com",
					},
				},
			},
		},
	}

	for _, ts := range tests {
		t.Run(ts.name, func(t *testing.T) {
			err := ts.spec.Validate()
			if d := cmp.Diff(err.Error(), ts.wantErr.Error()); d != "" {
				t.Errorf("Validate/%s (-want, +got) = %v", ts.name, d)
			}
		})
	}
}
<commit_msg>Remove TODO<commit_after>package v1alpha1

import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/knative/pkg/apis"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestTaskRunValidate(t *testing.T) {
	tests := []struct {
		name string
		task TaskRun
		want *apis.FieldError
	}{
		{
			name: "invalid taskspec",
			task: TaskRun{
				ObjectMeta: metav1.ObjectMeta{
					Name: "taskmetaname",
				},
			},
			want: apis.ErrMissingField("spec"),
		},
		{
			name: "invalid taskrun metadata",
			task: TaskRun{
				ObjectMeta: metav1.ObjectMeta{
					Name: "task.name",
				},
			},
			want: &apis.FieldError{
				Message: "Invalid resource name: special character . must not be present",
				Paths:   []string{"metadata.name"},
			},
		},
	}

	for _, ts := range tests {
		t.Run(ts.name, func(t *testing.T) {
			err := ts.task.Validate()
			if d := cmp.Diff(err.Error(), ts.want.Error()); d != "" {
				t.Errorf("Validate/%s (-want, +got) = %v", ts.name, d)
			}
		})
	}
}

func TestTaskRunSpecValidate(t *testing.T) {
	tests := []struct {
		name    string
		spec    *TaskRunSpec
		wantErr *apis.FieldError
	}{
		{
			name:    "invalid taskspec",
			spec:    &TaskRunSpec{},
			wantErr: apis.ErrMissingField("spec"),
		},
		{
			name: "invalid taskref",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: TaskTriggerTypePipelineRun,
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.taskref.name"),
		},
		{
			name: "invalid taskref",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.trigger.triggerref.type"),
		},
		{
			name: "valid task trigger run type",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Trigger: TaskTrigger{
					TriggerRef: TaskTriggerRef{
						Type: TaskTriggerTypePipelineRun,
					},
				},
			},
		},
		{
			name: "valid task inputs",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Params: []Param{{
						Name:  "name",
						Value: "value",
					}},
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
				},
			},
		},
		{
			name: "invalid task inputs",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}, {
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.Inputs.Resources.Name"),
		},
		{
			name: "invalid task input params",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Inputs: TaskRunInputs{
					Resources: []PipelineResourceVersion{{
						Version: "testv1",
						ResourceRef: PipelineResourceRef{
							Name: "testresource",
						},
					}},
					Params: []Param{{
						Name:  "name",
						Value: "value",
					}, {
						Name:  "name",
						Value: "value",
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.inputs.params"),
		},
		{
			name: "invalid task output type",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Name: "resourceName",
						Type: "invalidtype",
					}},
				},
			},
			wantErr: apis.ErrInvalidValue("invalidtype", "spec.Outputs.Resources.resourceName.Type"),
		},
		{
			name: "duplicate task output name",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Type: "git",
						Name: "resource1",
					}, {
						Type: "git",
						Name: "resource1",
					}},
				},
			},
			wantErr: apis.ErrMultipleOneOf("spec.Outputs.Resources.Name"),
		},
		{
			name: "valid task output",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Outputs: Outputs{
					Resources: []TaskResource{{
						Type: "git",
					}},
				},
			},
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Logs: ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.logs.Type"),
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.runs.Type"),
		},
		{
			name: "invalid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Tests: &ResultTarget{
						Name: "resultlogs",
						Type: "wrongtype",
					},
				},
			},
			wantErr: apis.ErrInvalidValue("wrongtype", "spec.results.tests.Type"),
		},
		{
			name: "invalid task type result name",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "",
						Type: ResultTargetTypeGCS,
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.results.runs.name"),
		},
		{
			name: "invalid task type result url",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "resultrunname",
						Type: ResultTargetTypeGCS,
						URL:  "",
					},
				},
			},
			wantErr: apis.ErrMissingField("spec.results.runs.URL"),
		},
		{
			name: "valid task type result",
			spec: &TaskRunSpec{
				TaskRef: TaskRef{
					Name: "taskrefname",
				},
				Results: Results{
					Runs: ResultTarget{
						Name: "testname",
						Type: ResultTargetTypeGCS,
						URL:  "http://github.com",
					},
				},
			},
		},
	}

	for _, ts := range tests {
		t.Run(ts.name, func(t *testing.T) {
			err := ts.spec.Validate()
			if d := cmp.Diff(err.Error(), ts.wantErr.Error()); d != "" {
				t.Errorf("Validate/%s (-want, +got) = %v", ts.name, d)
			}
		})
	}
}
<|endoftext|>


<commit_before>package bootkube

import (
	"text/template"
)

var (
	// CVOOverrides is the constant to represent contents of cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	CVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: clusterversion.openshift.io/v1
kind: CVOConfig
metadata:
  namespace: openshift-cluster-version
  name: cluster-version-operator
upstream: http://localhost:8080/graph
channel: fast
clusterID: {{.CVOClusterID}}
overrides:
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-network-operator
  name: cluster-network-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with tectonic-ingress-controller-operator
  namespace: openshift-ingress-operator
  name: ingress-operator
  unmanaged: true
- kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: APIService                    # packages.apps.redhat.com fails to start properly
  name: v1alpha1.packages.apps.redhat.com
  unmanaged: true
- kind: Deployment                    # still testing this new component
  namespace: openshift-pod-checkpointer
  name: pod-checkpointer-operator
  unmanaged: true
`))
)
<commit_msg>cvo-overrides: fix namespace for openshift-pod-checkpointer<commit_after>package bootkube

import (
	"text/template"
)

var (
	// CVOOverrides is the constant to represent contents of cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	CVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: clusterversion.openshift.io/v1
kind: CVOConfig
metadata:
  namespace: openshift-cluster-version
  name: cluster-version-operator
upstream: http://localhost:8080/graph
channel: fast
clusterID: {{.CVOClusterID}}
overrides:
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-network-operator
  name: cluster-network-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with tectonic-ingress-controller-operator
  namespace: openshift-ingress-operator
  name: ingress-operator
  unmanaged: true
- kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: APIService                    # packages.apps.redhat.com fails to start properly
  name: v1alpha1.packages.apps.redhat.com
  unmanaged: true
- kind: Deployment                    # still testing this new component
  namespace: kube-system
  name: pod-checkpointer-operator
  unmanaged: true
`))
)
<|endoftext|>