Use ConfigMap to store operator's config
This commit is contained in:
		
							parent
							
								
									47e3e29a56
								
							
						
					
					
						commit
						da438aab3a
					
				
							
								
								
									
										30
									
								
								cmd/main.go
								
								
								
								
							
							
						
						
									
										30
									
								
								cmd/main.go
								
								
								
								
							| 
						 | 
					@ -9,6 +9,7 @@ import (
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/controller"
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/controller"
 | 
				
			||||||
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/util/config"
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/util/config"
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/util/k8sutil"
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/util/k8sutil"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -16,9 +17,9 @@ import (
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	KubeConfigFile string
 | 
						KubeConfigFile string
 | 
				
			||||||
	podNamespace   string
 | 
						podNamespace   string
 | 
				
			||||||
 | 
						configMapName  spec.NamespacedName
 | 
				
			||||||
	OutOfCluster   bool
 | 
						OutOfCluster   bool
 | 
				
			||||||
	version        string
 | 
						version        string
 | 
				
			||||||
	cfg            *config.Config
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
| 
						 | 
					@ -27,11 +28,14 @@ func init() {
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	podNamespace = os.Getenv("MY_POD_NAMESPACE")
 | 
						podNamespace = os.Getenv("MY_POD_NAMESPACE")
 | 
				
			||||||
	if len(podNamespace) == 0 {
 | 
						if podNamespace == "" {
 | 
				
			||||||
		podNamespace = "default"
 | 
							podNamespace = "default"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = config.LoadFromEnv()
 | 
						configMap := os.Getenv("CONFIG_MAP_NAME")
 | 
				
			||||||
 | 
						if configMap != "" {
 | 
				
			||||||
 | 
							configMapName.Decode(configMap)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ControllerConfig() *controller.Config {
 | 
					func ControllerConfig() *controller.Config {
 | 
				
			||||||
| 
						 | 
					@ -48,16 +52,15 @@ func ControllerConfig() *controller.Config {
 | 
				
			||||||
	restClient, err := k8sutil.KubernetesRestClient(restConfig)
 | 
						restClient, err := k8sutil.KubernetesRestClient(restConfig)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &controller.Config{
 | 
						return &controller.Config{
 | 
				
			||||||
		PodNamespace: podNamespace, //TODO: move to config.Config
 | 
					 | 
				
			||||||
		KubeClient: client,
 | 
							KubeClient: client,
 | 
				
			||||||
		RestClient: restClient,
 | 
							RestClient: restClient,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
						configMapData := make(map[string]string)
 | 
				
			||||||
	log.SetOutput(os.Stdout)
 | 
						log.SetOutput(os.Stdout)
 | 
				
			||||||
	log.Printf("Spilo operator %s\n", version)
 | 
						log.Printf("Spilo operator %s\n", version)
 | 
				
			||||||
	log.Printf("Config: %s", cfg.MustMarshal())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sigs := make(chan os.Signal, 1)
 | 
						sigs := make(chan os.Signal, 1)
 | 
				
			||||||
	stop := make(chan struct{})
 | 
						stop := make(chan struct{})
 | 
				
			||||||
| 
						 | 
					@ -67,6 +70,23 @@ func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	controllerConfig := ControllerConfig()
 | 
						controllerConfig := ControllerConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if configMapName != (spec.NamespacedName{}) {
 | 
				
			||||||
 | 
							configMap, err := controllerConfig.KubeClient.ConfigMaps(configMapName.Namespace).Get(configMapName.Name)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							configMapData = configMap.Data
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							log.Printf("No ConfigMap specified. Loading default values")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if configMapData["namespace"] == "" { // Namespace in ConfigMap has priority over env var
 | 
				
			||||||
 | 
							configMapData["namespace"] = podNamespace
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cfg := config.NewFromMap(configMapData)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Printf("Config: %s", cfg.MustMarshal())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := controller.New(controllerConfig, cfg)
 | 
						c := controller.New(controllerConfig, cfg)
 | 
				
			||||||
	c.Run(stop, wg)
 | 
						c.Run(stop, wg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
hash: 9cb22736d27cb74bb0f674c5e57954c8fd14e4b5cae0b2e22ead9f10728f91f8
 | 
					hash: de07f359cf295197b1663e28cb7a9652c1bb4b9ddca7e70e4e605410b43e4e5f
 | 
				
			||||||
updated: 2017-04-10T15:33:31.332520218+02:00
 | 
					updated: 2017-04-19T11:22:12.486616201+02:00
 | 
				
			||||||
imports:
 | 
					imports:
 | 
				
			||||||
- name: cloud.google.com/go
 | 
					- name: cloud.google.com/go
 | 
				
			||||||
  version: 3b1ae45394a234c385be014e9a488f2bb6eef821
 | 
					  version: 3b1ae45394a234c385be014e9a488f2bb6eef821
 | 
				
			||||||
| 
						 | 
					@ -75,12 +75,10 @@ imports:
 | 
				
			||||||
  version: 2eee05ed794112d45db504eb05aa693efd2b8b09
 | 
					  version: 2eee05ed794112d45db504eb05aa693efd2b8b09
 | 
				
			||||||
- name: github.com/juju/ratelimit
 | 
					- name: github.com/juju/ratelimit
 | 
				
			||||||
  version: 77ed1c8a01217656d2080ad51981f6e99adaa177
 | 
					  version: 77ed1c8a01217656d2080ad51981f6e99adaa177
 | 
				
			||||||
- name: github.com/kelseyhightower/envconfig
 | 
					 | 
				
			||||||
  version: 8bf4bbfc795e2c7c8a5ea47b707453ed019e2ad4
 | 
					 | 
				
			||||||
- name: github.com/kr/text
 | 
					- name: github.com/kr/text
 | 
				
			||||||
  version: 7cafcd837844e784b526369c9bce262804aebc60
 | 
					  version: 7cafcd837844e784b526369c9bce262804aebc60
 | 
				
			||||||
- name: github.com/lib/pq
 | 
					- name: github.com/lib/pq
 | 
				
			||||||
  version: 0477eb88c5ca4009cb281f13c90633375b6a9987
 | 
					  version: 2704adc878c21e1329f46f6e56a1c387d788ff94
 | 
				
			||||||
  subpackages:
 | 
					  subpackages:
 | 
				
			||||||
  - oid
 | 
					  - oid
 | 
				
			||||||
- name: github.com/mailru/easyjson
 | 
					- name: github.com/mailru/easyjson
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,5 +27,4 @@ import:
 | 
				
			||||||
  - rest
 | 
					  - rest
 | 
				
			||||||
  - tools/cache
 | 
					  - tools/cache
 | 
				
			||||||
  - tools/clientcmd
 | 
					  - tools/clientcmd
 | 
				
			||||||
- package: github.com/kelseyhightower/envconfig
 | 
					 | 
				
			||||||
- package: github.com/motomux/pretty
 | 
					- package: github.com/motomux/pretty
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					apiVersion: v1
 | 
				
			||||||
 | 
					kind: ConfigMap
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: postgres-operator
 | 
				
			||||||
 | 
					data:
 | 
				
			||||||
 | 
					  service_account_name: operator
 | 
				
			||||||
 | 
					  cluster_labels: application:spilo
 | 
				
			||||||
 | 
					  cluster_name_label: version
 | 
				
			||||||
 | 
					  pod_role_label: spilo-role
 | 
				
			||||||
 | 
					  db_hosted_zone: db.example.com
 | 
				
			||||||
 | 
					  dns_name_format: '%s.%s.staging.%s'
 | 
				
			||||||
 | 
					  docker_image: registry.opensource.zalan.do/acid/spilo-9.6:1.2-p12
 | 
				
			||||||
 | 
					  etcd_host: etcd-client.default.svc.cluster.local:2379
 | 
				
			||||||
 | 
					  infrastructure_roles_secret_name: postgresql-infrastructure-roles
 | 
				
			||||||
 | 
					  oauth_token_secret_name: postgresql-operator
 | 
				
			||||||
 | 
					  pam_configuration: |
 | 
				
			||||||
 | 
					    https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees
 | 
				
			||||||
 | 
					  pam_role_name: zalandos
 | 
				
			||||||
 | 
					  pod_deletion_wait_timeout: 10m
 | 
				
			||||||
 | 
					  pod_label_wait_timeout: 10m
 | 
				
			||||||
 | 
					  ready_wait_interval: 3s
 | 
				
			||||||
 | 
					  ready_wait_timeout: 30s
 | 
				
			||||||
 | 
					  replication_username: replication
 | 
				
			||||||
 | 
					  resource_check_interval: 3s
 | 
				
			||||||
 | 
					  resource_check_timeout: 10m
 | 
				
			||||||
 | 
					  resync_period: 5m
 | 
				
			||||||
 | 
					  resync_period_pod: 5m
 | 
				
			||||||
 | 
					  super_username: postgres
 | 
				
			||||||
 | 
					  teams_api_url: https://teams.example.com/api/
 | 
				
			||||||
| 
						 | 
					@ -14,49 +14,9 @@ spec:
 | 
				
			||||||
      - name: postgres-operator
 | 
					      - name: postgres-operator
 | 
				
			||||||
        image: pierone.example.com/acid/postgres-operator:0.1
 | 
					        image: pierone.example.com/acid/postgres-operator:0.1
 | 
				
			||||||
        env:
 | 
					        env:
 | 
				
			||||||
        - name: MY_POD_NAMESPACE #TODO: use PGOP_ prefix
 | 
					        - name: MY_POD_NAMESPACE
 | 
				
			||||||
          valueFrom:
 | 
					          valueFrom:
 | 
				
			||||||
            fieldRef:
 | 
					            fieldRef:
 | 
				
			||||||
              fieldPath: metadata.namespace
 | 
					              fieldPath: metadata.namespace
 | 
				
			||||||
        - name: PGOP_SERVICE_ACCOUNT_NAME
 | 
					        - name: CONFIG_MAP_NAME
 | 
				
			||||||
          valueFrom:
 | 
					          value: "postgres-operator"
 | 
				
			||||||
            fieldRef:
 | 
					 | 
				
			||||||
              fieldPath: spec.serviceAccountName
 | 
					 | 
				
			||||||
        - name: PGOP_READY_WAIT_INTERVAL
 | 
					 | 
				
			||||||
          value: "3s"
 | 
					 | 
				
			||||||
        - name: PGOP_READY_WAIT_TIMEOUT
 | 
					 | 
				
			||||||
          value: "30s"
 | 
					 | 
				
			||||||
        - name: PGOP_RESYNC_PERIOD
 | 
					 | 
				
			||||||
          value: "5m"
 | 
					 | 
				
			||||||
        - name: PGOP_RESYNC_PERIOD_POD
 | 
					 | 
				
			||||||
          value: "5m"
 | 
					 | 
				
			||||||
        - name: PGOP_RESOURCE_CHECK_INTERVAL
 | 
					 | 
				
			||||||
          value: "3s"
 | 
					 | 
				
			||||||
        - name: PGOP_RESOURCE_CHECK_TIMEOUT
 | 
					 | 
				
			||||||
          value: "10m"
 | 
					 | 
				
			||||||
        - name: PGOP_POD_LABEL_WAIT_TIMEOUT
 | 
					 | 
				
			||||||
          value: "10m"
 | 
					 | 
				
			||||||
        - name: PGOP_POD_DELETION_WAIT_TIMEOUT
 | 
					 | 
				
			||||||
          value: "10m"
 | 
					 | 
				
			||||||
        - name: PGOP_PAM_ROLE_NAME
 | 
					 | 
				
			||||||
          value: "zalandos"
 | 
					 | 
				
			||||||
        - name: PGOP_PAM_CONFIGURATION
 | 
					 | 
				
			||||||
          value: "https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"
 | 
					 | 
				
			||||||
        - name: PGOP_TEAMS_API_URL
 | 
					 | 
				
			||||||
          value: "https://teams.example.com/api/"
 | 
					 | 
				
			||||||
        - name: PGOP_OAUTH_TOKEN_SECRET_NAME
 | 
					 | 
				
			||||||
          value: "postgresql-operator"
 | 
					 | 
				
			||||||
        - name: PGOP_SUPER_USERNAME
 | 
					 | 
				
			||||||
          value: "postgres"
 | 
					 | 
				
			||||||
        - name: PGOP_REPLICATION_USERNAME
 | 
					 | 
				
			||||||
          value: "replication"
 | 
					 | 
				
			||||||
        - name: PGOP_ETCD_HOST
 | 
					 | 
				
			||||||
          value: "etcd-client.default.svc.cluster.local:2379"
 | 
					 | 
				
			||||||
        - name: PGOP_DOCKER_IMAGE
 | 
					 | 
				
			||||||
          value: "registry.opensource.zalan.do/acid/spilo-9.6:1.2-p12"
 | 
					 | 
				
			||||||
        - name: PGOP_DB_HOSTED_ZONE
 | 
					 | 
				
			||||||
          value: "db.example.com"
 | 
					 | 
				
			||||||
        - name: PGOP_DNS_NAME_FORMAT
 | 
					 | 
				
			||||||
          value: "%s.%s.staging.%s"
 | 
					 | 
				
			||||||
        - name: PGOP_INFRASTRUCTURE_ROLES_SECRET_NAME
 | 
					 | 
				
			||||||
          value: "postgresql-infrastructure-roles"
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ apiVersion: "acid.zalan.do/v1"
 | 
				
			||||||
kind: "Postgresql"
 | 
					kind: "Postgresql"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
metadata:
 | 
					metadata:
 | 
				
			||||||
  name: testcluster
 | 
					  name: acid-testcluster
 | 
				
			||||||
spec:
 | 
					spec:
 | 
				
			||||||
  teamId: "ACID"
 | 
					  teamId: "ACID"
 | 
				
			||||||
  volume:
 | 
					  volume:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,7 +183,7 @@ func (c *Cluster) recreatePods() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var masterPod v1.Pod
 | 
						var masterPod v1.Pod
 | 
				
			||||||
	for _, pod := range pods.Items {
 | 
						for _, pod := range pods.Items {
 | 
				
			||||||
		role := util.PodSpiloRole(&pod)
 | 
							role := c.PodSpiloRole(&pod)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if role == constants.PodRoleMaster {
 | 
							if role == constants.PodRoleMaster {
 | 
				
			||||||
			masterPod = pod
 | 
								masterPod = pod
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,7 +103,7 @@ func (c *Cluster) waitForPodLabel(podEvents chan spec.PodEvent) error {
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case podEvent := <-podEvents:
 | 
							case podEvent := <-podEvents:
 | 
				
			||||||
			role := util.PodSpiloRole(podEvent.CurPod)
 | 
								role := c.PodSpiloRole(podEvent.CurPod)
 | 
				
			||||||
			// We cannot assume any role of the newly created pod. Normally, for a multi-pod cluster
 | 
								// We cannot assume any role of the newly created pod. Normally, for a multi-pod cluster
 | 
				
			||||||
			// we should observe the 'replica' value, but it could be that some pods are not allowed
 | 
								// we should observe the 'replica' value, but it could be that some pods are not allowed
 | 
				
			||||||
			// to promote, therefore, the new pod could be a master as well.
 | 
								// to promote, therefore, the new pod could be a master as well.
 | 
				
			||||||
| 
						 | 
					@ -156,10 +156,14 @@ func (c *Cluster) waitPodLabelsReady() error {
 | 
				
			||||||
		LabelSelector: ls.String(),
 | 
							LabelSelector: ls.String(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	masterListOption := v1.ListOptions{
 | 
						masterListOption := v1.ListOptions{
 | 
				
			||||||
		LabelSelector: labels.Merge(ls, labels.Set{constants.SpiloRoleLabel: constants.PodRoleMaster}).String(),
 | 
							LabelSelector: labels.Merge(ls, labels.Set{
 | 
				
			||||||
 | 
								c.OpConfig.PodRoleLabel: constants.PodRoleMaster,
 | 
				
			||||||
 | 
							}).String(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	replicaListOption := v1.ListOptions{
 | 
						replicaListOption := v1.ListOptions{
 | 
				
			||||||
		LabelSelector: labels.Merge(ls, labels.Set{constants.SpiloRoleLabel: constants.PodRoleReplica}).String(),
 | 
							LabelSelector: labels.Merge(ls, labels.Set{
 | 
				
			||||||
 | 
								c.OpConfig.PodRoleLabel: constants.PodRoleReplica,
 | 
				
			||||||
 | 
							}).String(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pods, err := c.KubeClient.Pods(namespace).List(listOptions)
 | 
						pods, err := c.KubeClient.Pods(namespace).List(listOptions)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -203,10 +207,10 @@ func (c *Cluster) waitStatefulsetPodsReady() error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Cluster) labelsSet() labels.Set {
 | 
					func (c *Cluster) labelsSet() labels.Set {
 | 
				
			||||||
	return labels.Set{
 | 
						lbls := c.OpConfig.ClusterLabels
 | 
				
			||||||
		constants.ApplicationNameLabel: constants.ApplicationNameLabelValue,
 | 
						lbls[c.OpConfig.ClusterNameLabel] = c.Metadata.Name
 | 
				
			||||||
		constants.ClusterNameLabel:     c.Metadata.Name,
 | 
					
 | 
				
			||||||
	}
 | 
						return labels.Set(lbls)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Cluster) dnsName() string {
 | 
					func (c *Cluster) dnsName() string {
 | 
				
			||||||
| 
						 | 
					@ -228,7 +232,7 @@ func (c *Cluster) credentialSecretName(username string) string {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Cluster) deleteEtcdKey() error {
 | 
					func (c *Cluster) deleteEtcdKey() error {
 | 
				
			||||||
	etcdKey := fmt.Sprintf("/service/%s", c.Metadata.Name)
 | 
						etcdKey := fmt.Sprintf("/%s/%s", c.OpConfig.EtcdScope, c.Metadata.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//TODO: retry multiple times
 | 
						//TODO: retry multiple times
 | 
				
			||||||
	resp, err := c.EtcdClient.Delete(context.Background(),
 | 
						resp, err := c.EtcdClient.Delete(context.Background(),
 | 
				
			||||||
| 
						 | 
					@ -245,3 +249,7 @@ func (c *Cluster) deleteEtcdKey() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Cluster) PodSpiloRole(pod *v1.Pod) string {
 | 
				
			||||||
 | 
						return pod.Labels[c.OpConfig.PodRoleLabel]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	PodNamespace        string
 | 
					 | 
				
			||||||
	KubeClient          *kubernetes.Clientset
 | 
						KubeClient          *kubernetes.Clientset
 | 
				
			||||||
	RestClient          *rest.RESTClient
 | 
						RestClient          *rest.RESTClient
 | 
				
			||||||
	EtcdClient          etcdclient.KeysAPI
 | 
						EtcdClient          etcdclient.KeysAPI
 | 
				
			||||||
| 
						 | 
					@ -63,7 +62,6 @@ func (c *Controller) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.initController()
 | 
						c.initController()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.logger.Infof("'%s' namespace will be watched", c.PodNamespace)
 | 
					 | 
				
			||||||
	go c.runInformers(stopCh)
 | 
						go c.runInformers(stopCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.logger.Info("Started working in background")
 | 
						c.logger.Info("Started working in background")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ func (c *Controller) podListFunc(options api.ListOptions) (runtime.Object, error
 | 
				
			||||||
		TimeoutSeconds:  options.TimeoutSeconds,
 | 
							TimeoutSeconds:  options.TimeoutSeconds,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c.KubeClient.CoreV1().Pods(c.PodNamespace).List(opts)
 | 
						return c.KubeClient.CoreV1().Pods(c.opConfig.Namespace).List(opts)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Controller) podWatchFunc(options api.ListOptions) (watch.Interface, error) {
 | 
					func (c *Controller) podWatchFunc(options api.ListOptions) (watch.Interface, error) {
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,7 @@ func (c *Controller) podWatchFunc(options api.ListOptions) (watch.Interface, err
 | 
				
			||||||
		TimeoutSeconds:  options.TimeoutSeconds,
 | 
							TimeoutSeconds:  options.TimeoutSeconds,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c.KubeClient.CoreV1Client.Pods(c.PodNamespace).Watch(opts)
 | 
						return c.KubeClient.CoreV1Client.Pods(c.opConfig.Namespace).Watch(opts)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Controller) podAdd(obj interface{}) {
 | 
					func (c *Controller) podAdd(obj interface{}) {
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,7 @@ func (c *Controller) podAdd(obj interface{}) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	podEvent := spec.PodEvent{
 | 
						podEvent := spec.PodEvent{
 | 
				
			||||||
		ClusterName: util.PodClusterName(pod),
 | 
							ClusterName: c.PodClusterName(pod),
 | 
				
			||||||
		PodName:     util.NameFromMeta(pod.ObjectMeta),
 | 
							PodName:     util.NameFromMeta(pod.ObjectMeta),
 | 
				
			||||||
		CurPod:      pod,
 | 
							CurPod:      pod,
 | 
				
			||||||
		EventType:   spec.PodEventAdd,
 | 
							EventType:   spec.PodEventAdd,
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,7 @@ func (c *Controller) podUpdate(prev, cur interface{}) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	podEvent := spec.PodEvent{
 | 
						podEvent := spec.PodEvent{
 | 
				
			||||||
		ClusterName: util.PodClusterName(curPod),
 | 
							ClusterName: c.PodClusterName(curPod),
 | 
				
			||||||
		PodName:     util.NameFromMeta(curPod.ObjectMeta),
 | 
							PodName:     util.NameFromMeta(curPod.ObjectMeta),
 | 
				
			||||||
		PrevPod:     prevPod,
 | 
							PrevPod:     prevPod,
 | 
				
			||||||
		CurPod:      curPod,
 | 
							CurPod:      curPod,
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,7 @@ func (c *Controller) podDelete(obj interface{}) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	podEvent := spec.PodEvent{
 | 
						podEvent := spec.PodEvent{
 | 
				
			||||||
		ClusterName: util.PodClusterName(pod),
 | 
							ClusterName: c.PodClusterName(pod),
 | 
				
			||||||
		PodName:     util.NameFromMeta(pod.ObjectMeta),
 | 
							PodName:     util.NameFromMeta(pod.ObjectMeta),
 | 
				
			||||||
		CurPod:      pod,
 | 
							CurPod:      pod,
 | 
				
			||||||
		EventType:   spec.PodEventDelete,
 | 
							EventType:   spec.PodEventDelete,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ import (
 | 
				
			||||||
func (c *Controller) clusterListFunc(options api.ListOptions) (runtime.Object, error) {
 | 
					func (c *Controller) clusterListFunc(options api.ListOptions) (runtime.Object, error) {
 | 
				
			||||||
	c.logger.Info("Getting list of currently running clusters")
 | 
						c.logger.Info("Getting list of currently running clusters")
 | 
				
			||||||
	object, err := c.RestClient.Get().
 | 
						object, err := c.RestClient.Get().
 | 
				
			||||||
		Namespace(c.PodNamespace).
 | 
							Namespace(c.opConfig.Namespace).
 | 
				
			||||||
		Resource(constants.ResourceName).
 | 
							Resource(constants.ResourceName).
 | 
				
			||||||
		VersionedParams(&options, api.ParameterCodec).
 | 
							VersionedParams(&options, api.ParameterCodec).
 | 
				
			||||||
		FieldsSelectorParam(fields.Everything()).
 | 
							FieldsSelectorParam(fields.Everything()).
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,7 @@ func (c *Controller) clusterListFunc(options api.ListOptions) (runtime.Object, e
 | 
				
			||||||
func (c *Controller) clusterWatchFunc(options api.ListOptions) (watch.Interface, error) {
 | 
					func (c *Controller) clusterWatchFunc(options api.ListOptions) (watch.Interface, error) {
 | 
				
			||||||
	return c.RestClient.Get().
 | 
						return c.RestClient.Get().
 | 
				
			||||||
		Prefix("watch").
 | 
							Prefix("watch").
 | 
				
			||||||
		Namespace(c.PodNamespace).
 | 
							Namespace(c.opConfig.Namespace).
 | 
				
			||||||
		Resource(constants.ResourceName).
 | 
							Resource(constants.ResourceName).
 | 
				
			||||||
		VersionedParams(&options, api.ParameterCodec).
 | 
							VersionedParams(&options, api.ParameterCodec).
 | 
				
			||||||
		FieldsSelectorParam(fields.Everything()).
 | 
							FieldsSelectorParam(fields.Everything()).
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ func (c *Controller) createTPR() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	restClient := c.RestClient
 | 
						restClient := c.RestClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return k8sutil.WaitTPRReady(restClient, c.opConfig.TPR.ReadyWaitInterval, c.opConfig.TPR.ReadyWaitTimeout, c.PodNamespace)
 | 
						return k8sutil.WaitTPRReady(restClient, c.opConfig.TPR.ReadyWaitInterval, c.opConfig.TPR.ReadyWaitTimeout, c.opConfig.Namespace)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Controller) getInfrastructureRoles() (result map[string]spec.PgUser, err error) {
 | 
					func (c *Controller) getInfrastructureRoles() (result map[string]spec.PgUser, err error) {
 | 
				
			||||||
| 
						 | 
					@ -125,3 +125,14 @@ Users:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result, nil
 | 
						return result, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Controller) PodClusterName(pod *v1.Pod) spec.NamespacedName {
 | 
				
			||||||
 | 
						if name, ok := pod.Labels[c.opConfig.ClusterNameLabel]; ok {
 | 
				
			||||||
 | 
							return spec.NamespacedName{
 | 
				
			||||||
 | 
								Namespace: pod.Namespace,
 | 
				
			||||||
 | 
								Name:      name,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spec.NamespacedName{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,64 +2,53 @@ package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
				
			||||||
	"github.com/kelseyhightower/envconfig"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TPR struct {
 | 
					type TPR struct {
 | 
				
			||||||
	ReadyWaitInterval time.Duration `split_words:"true" default:"3s"`
 | 
						ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
 | 
				
			||||||
	ReadyWaitTimeout  time.Duration `split_words:"true" default:"30s"`
 | 
						ReadyWaitTimeout  time.Duration `name:"ready_wait_timeout" default:"30s"`
 | 
				
			||||||
	ResyncPeriod      time.Duration `split_words:"true" default:"5m"`
 | 
						ResyncPeriod      time.Duration `name:"resync_period" default:"5m"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Resources struct {
 | 
					type Resources struct {
 | 
				
			||||||
	ResyncPeriodPod        time.Duration `split_words:"true" default:"5m"`
 | 
						ResyncPeriodPod        time.Duration     `name:"resync_period_pod" default:"5m"`
 | 
				
			||||||
	ResourceCheckInterval  time.Duration `split_words:"true" default:"3s"`
 | 
						ResourceCheckInterval  time.Duration     `name:"resource_check_interval" default:"3s"`
 | 
				
			||||||
	ResourceCheckTimeout   time.Duration `split_words:"true" default:"10m"`
 | 
						ResourceCheckTimeout   time.Duration     `name:"resource_check_timeout" default:"10m"`
 | 
				
			||||||
	PodLabelWaitTimeout    time.Duration `split_words:"true" default:"10m"`
 | 
						PodLabelWaitTimeout    time.Duration     `name:"pod_label_wait_timeout" default:"10m"`
 | 
				
			||||||
	PodDeletionWaitTimeout time.Duration `split_words:"true" default:"10m"`
 | 
						PodDeletionWaitTimeout time.Duration     `name:"pod_deletion_wait_timeout" default:"10m"`
 | 
				
			||||||
 | 
						ClusterLabels          map[string]string `name:"cluster_labels" default:"application:spilo"`
 | 
				
			||||||
 | 
						ClusterNameLabel       string            `name:"cluster_name_label" default:"cluster-name"`
 | 
				
			||||||
 | 
						PodRoleLabel           string            `name:"pod_role_label" default:"spilo-role"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Auth struct {
 | 
					type Auth struct {
 | 
				
			||||||
	PamRoleName                   string              `split_words:"true" default:"zalandos"`
 | 
						PamRoleName                   string              `name:"pam_rol_name" default:"zalandos"`
 | 
				
			||||||
	PamConfiguration              string              `split_words:"true" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
 | 
						PamConfiguration              string              `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
 | 
				
			||||||
	TeamsAPIUrl                   string              `envconfig:"teams_api_url" default:"https://teams.example.com/api/"`
 | 
						TeamsAPIUrl                   string              `name:"teams_api_url" default:"https://teams.example.com/api/"`
 | 
				
			||||||
	OAuthTokenSecretName          spec.NamespacedName `envconfig:"oauth_token_secret_name" default:"postgresql-operator"`
 | 
						OAuthTokenSecretName          spec.NamespacedName `name:"oauth_token_secret_name" default:"postgresql-operator"`
 | 
				
			||||||
	InfrastructureRolesSecretName spec.NamespacedName `split_words:"true"`
 | 
						InfrastructureRolesSecretName spec.NamespacedName `name:"infrastructure_roles_secret_name"`
 | 
				
			||||||
	SuperUsername                 string              `split_words:"true" default:"postgres"`
 | 
						SuperUsername                 string              `name:"super_username" default:"postgres"`
 | 
				
			||||||
	ReplicationUsername           string              `split_words:"true" default:"replication"`
 | 
						ReplicationUsername           string              `name:"replication_username" default:"replication"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	TPR
 | 
						TPR
 | 
				
			||||||
	Resources
 | 
						Resources
 | 
				
			||||||
	Auth
 | 
						Auth
 | 
				
			||||||
	EtcdHost           string `split_words:"true" default:"etcd-client.default.svc.cluster.local:2379"`
 | 
						Namespace          string `name:"namespace"`
 | 
				
			||||||
	DockerImage        string `split_words:"true" default:"registry.opensource.zalan.do/acid/spilo-9.6:1.2-p12"`
 | 
						EtcdHost           string `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"`
 | 
				
			||||||
	ServiceAccountName string `split_words:"true" default:"operator"`
 | 
						DockerImage        string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-9.6:1.2-p12"`
 | 
				
			||||||
	DbHostedZone       string `split_words:"true" default:"db.example.com"`
 | 
						ServiceAccountName string `name:"service_account_name" default:"operator"`
 | 
				
			||||||
	EtcdScope          string `split_words:"true" default:"service"`
 | 
						DbHostedZone       string `name:"db_hosted_zone" default:"db.example.com"`
 | 
				
			||||||
	WALES3Bucket       string `envconfig:"wal_s3_bucket"`
 | 
						EtcdScope          string `name:"etcd_scope" default:"service"`
 | 
				
			||||||
	KubeIAMRole        string `envconfig:"kube_iam_role"`
 | 
						WALES3Bucket       string `name:"wal_s3_bucket"`
 | 
				
			||||||
	DebugLogging       bool   `split_words:"true" default:"false"`
 | 
						KubeIAMRole        string `name:"kube_iam_role"`
 | 
				
			||||||
	DNSNameFormat      string `envconfig:"dns_name_format" default:"%s.%s.%s"`
 | 
						DebugLogging       bool   `name:"debug_logging" default:"false"`
 | 
				
			||||||
}
 | 
						DNSNameFormat      string `name:"dns_name_format" default:"%s.%s.%s"`
 | 
				
			||||||
 | 
					 | 
				
			||||||
func LoadFromEnv() *Config {
 | 
					 | 
				
			||||||
	//TODO: maybe we should use ConfigMaps( https://kubernetes.io/docs/tasks/configure-pod-container/configmap/ ) instead?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var cfg Config
 | 
					 | 
				
			||||||
	err := envconfig.Process("PGOP", &cfg)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(fmt.Errorf("Can't read config: %v", err))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cfg.EtcdScope = strings.Trim(cfg.EtcdScope, "/")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &cfg
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c Config) MustMarshal() string {
 | 
					func (c Config) MustMarshal() string {
 | 
				
			||||||
| 
						 | 
					@ -70,3 +59,23 @@ func (c Config) MustMarshal() string {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return string(b)
 | 
						return string(b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewFromMap(m map[string]string) *Config {
 | 
				
			||||||
 | 
						cfg := Config{}
 | 
				
			||||||
 | 
						fields, _ := structFields(&cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, structField := range fields {
 | 
				
			||||||
 | 
							key := strings.ToLower(structField.Name)
 | 
				
			||||||
 | 
							value, ok := m[key]
 | 
				
			||||||
 | 
							if !ok && structField.Default != "" {
 | 
				
			||||||
 | 
								value = structField.Default
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err := processField(value, structField.Field)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &cfg
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,164 @@
 | 
				
			||||||
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Decoder interface {
 | 
				
			||||||
 | 
						Decode(value string) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type fieldInfo struct {
 | 
				
			||||||
 | 
						Name    string
 | 
				
			||||||
 | 
						Default string
 | 
				
			||||||
 | 
						Field   reflect.Value
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func decoderFrom(field reflect.Value) (d Decoder) {
 | 
				
			||||||
 | 
						// it may be impossible for a struct field to fail this check
 | 
				
			||||||
 | 
						if !field.CanInterface() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d, ok := field.Interface().(Decoder)
 | 
				
			||||||
 | 
						if !ok && field.CanAddr() {
 | 
				
			||||||
 | 
							d, ok = field.Addr().Interface().(Decoder)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return d
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// taken from github.com/kelseyhightower/envconfig
 | 
				
			||||||
 | 
					func structFields(spec interface{}) ([]fieldInfo, error) {
 | 
				
			||||||
 | 
						s := reflect.ValueOf(spec).Elem()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// over allocate an info array, we will extend if needed later
 | 
				
			||||||
 | 
						infos := make([]fieldInfo, 0, s.NumField())
 | 
				
			||||||
 | 
						for i := 0; i < s.NumField(); i++ {
 | 
				
			||||||
 | 
							f := s.Field(i)
 | 
				
			||||||
 | 
							ftype := s.Type().Field(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fieldName := ftype.Tag.Get("name")
 | 
				
			||||||
 | 
							if fieldName == "" {
 | 
				
			||||||
 | 
								fieldName = strings.ToLower(ftype.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Capture information about the config variable
 | 
				
			||||||
 | 
							info := fieldInfo{
 | 
				
			||||||
 | 
								Name:    fieldName,
 | 
				
			||||||
 | 
								Field:   f,
 | 
				
			||||||
 | 
								Default: ftype.Tag.Get("default"),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							infos = append(infos, info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if f.Kind() == reflect.Struct {
 | 
				
			||||||
 | 
								// honor Decode if present
 | 
				
			||||||
 | 
								if decoderFrom(f) == nil {
 | 
				
			||||||
 | 
									embeddedPtr := f.Addr().Interface()
 | 
				
			||||||
 | 
									embeddedInfos, err := structFields(embeddedPtr)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return nil, err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									infos = append(infos[:len(infos)-1], embeddedInfos...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return infos, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func processField(value string, field reflect.Value) error {
 | 
				
			||||||
 | 
						typ := field.Type()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder := decoderFrom(field)
 | 
				
			||||||
 | 
						if decoder != nil {
 | 
				
			||||||
 | 
							return decoder.Decode(value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if typ.Kind() == reflect.Ptr {
 | 
				
			||||||
 | 
							typ = typ.Elem()
 | 
				
			||||||
 | 
							if field.IsNil() {
 | 
				
			||||||
 | 
								field.Set(reflect.New(typ))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field = field.Elem()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch typ.Kind() {
 | 
				
			||||||
 | 
						case reflect.String:
 | 
				
			||||||
 | 
							field.SetString(value)
 | 
				
			||||||
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
 | 
							var (
 | 
				
			||||||
 | 
								val int64
 | 
				
			||||||
 | 
								err error
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
 | 
				
			||||||
 | 
								var d time.Duration
 | 
				
			||||||
 | 
								d, err = time.ParseDuration(value)
 | 
				
			||||||
 | 
								val = int64(d)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								val, err = strconv.ParseInt(value, 0, typ.Bits())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							field.SetInt(val)
 | 
				
			||||||
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
 | 
							val, err := strconv.ParseUint(value, 0, typ.Bits())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field.SetUint(val)
 | 
				
			||||||
 | 
						case reflect.Bool:
 | 
				
			||||||
 | 
							val, err := strconv.ParseBool(value)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field.SetBool(val)
 | 
				
			||||||
 | 
						case reflect.Float32, reflect.Float64:
 | 
				
			||||||
 | 
							val, err := strconv.ParseFloat(value, typ.Bits())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field.SetFloat(val)
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							vals := strings.Split(value, ",")
 | 
				
			||||||
 | 
							sl := reflect.MakeSlice(typ, len(vals), len(vals))
 | 
				
			||||||
 | 
							for i, val := range vals {
 | 
				
			||||||
 | 
								err := processField(val, sl.Index(i))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field.Set(sl)
 | 
				
			||||||
 | 
						case reflect.Map:
 | 
				
			||||||
 | 
							pairs := strings.Split(value, ",")
 | 
				
			||||||
 | 
							mp := reflect.MakeMap(typ)
 | 
				
			||||||
 | 
							for _, pair := range pairs {
 | 
				
			||||||
 | 
								kvpair := strings.Split(pair, ":")
 | 
				
			||||||
 | 
								if len(kvpair) != 2 {
 | 
				
			||||||
 | 
									return fmt.Errorf("invalid map item: %q", pair)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								k := reflect.New(typ.Key()).Elem()
 | 
				
			||||||
 | 
								err := processField(kvpair[0], k)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								v := reflect.New(typ.Elem()).Elem()
 | 
				
			||||||
 | 
								err = processField(kvpair[1], v)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								mp.SetMapIndex(k, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							field.Set(mp)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,4 @@ const (
 | 
				
			||||||
	ResourceName             = TPRName + "s"
 | 
						ResourceName             = TPRName + "s"
 | 
				
			||||||
	PodRoleMaster            = "master"
 | 
						PodRoleMaster            = "master"
 | 
				
			||||||
	PodRoleReplica           = "replica"
 | 
						PodRoleReplica           = "replica"
 | 
				
			||||||
	ApplicationNameLabel      = "application"
 | 
					 | 
				
			||||||
	ApplicationNameLabelValue = "spilo"
 | 
					 | 
				
			||||||
	SpiloRoleLabel            = "spilo-role"
 | 
					 | 
				
			||||||
	ClusterNameLabel          = "version"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,6 @@ import (
 | 
				
			||||||
	"k8s.io/client-go/pkg/api/v1"
 | 
						"k8s.io/client-go/pkg/api/v1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
						"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
				
			||||||
	"github.bus.zalan.do/acid/postgres-operator/pkg/util/constants"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
 | 
					var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
 | 
				
			||||||
| 
						 | 
					@ -37,21 +36,6 @@ func NameFromMeta(meta v1.ObjectMeta) spec.NamespacedName {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func PodClusterName(pod *v1.Pod) spec.NamespacedName {
 | 
					 | 
				
			||||||
	if name, ok := pod.Labels[constants.ClusterNameLabel]; ok {
 | 
					 | 
				
			||||||
		return spec.NamespacedName{
 | 
					 | 
				
			||||||
			Namespace: pod.Namespace,
 | 
					 | 
				
			||||||
			Name:      name,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return spec.NamespacedName{}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func PodSpiloRole(pod *v1.Pod) string {
 | 
					 | 
				
			||||||
	return pod.Labels[constants.SpiloRoleLabel]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func PGUserPassword(user spec.PgUser) string {
 | 
					func PGUserPassword(user spec.PgUser) string {
 | 
				
			||||||
	s := md5.Sum([]byte(user.Password + user.Name))
 | 
						s := md5.Sum([]byte(user.Password + user.Name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue