157 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
package cluster
 | 
						|
 | 
						|
// Postgres ThirdPartyResource object i.e. Spilo
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/Sirupsen/logrus"
 | 
						|
	"k8s.io/client-go/kubernetes"
 | 
						|
	"k8s.io/client-go/pkg/api/v1"
 | 
						|
	"k8s.io/client-go/rest"
 | 
						|
 | 
						|
	"github.bus.zalan.do/acid/postgres-operator/pkg/spec"
 | 
						|
	"github.bus.zalan.do/acid/postgres-operator/pkg/util"
 | 
						|
	"github.bus.zalan.do/acid/postgres-operator/pkg/util/constants"
 | 
						|
)
 | 
						|
 | 
						|
var patroniUsers = []string{"superuser", "replication", "admin"}
 | 
						|
 | 
						|
//TODO: remove struct duplication
 | 
						|
type Config struct {
 | 
						|
	Namespace  string
 | 
						|
	KubeClient *kubernetes.Clientset //TODO: move clients to the better place?
 | 
						|
	RestClient *rest.RESTClient
 | 
						|
}
 | 
						|
 | 
						|
type Cluster struct {
 | 
						|
	logger      *logrus.Entry
 | 
						|
	config      Config
 | 
						|
	etcdHost    string
 | 
						|
	dockerImage string
 | 
						|
	cluster     *spec.Postgresql
 | 
						|
	pgUsers     []pgUser
 | 
						|
}
 | 
						|
 | 
						|
type pgUser struct {
 | 
						|
	username string
 | 
						|
	secretKey string
 | 
						|
	password []byte
 | 
						|
	flags []string
 | 
						|
}
 | 
						|
 | 
						|
func New(cfg Config, spec *spec.Postgresql) *Cluster {
 | 
						|
	lg := logrus.WithField("pkg", "cluster").WithField("cluster-name", spec.Metadata.Name)
 | 
						|
 | 
						|
	//TODO: check if image exist
 | 
						|
	dockerImage := fmt.Sprintf("registry.opensource.zalan.do/acid/spilo-%s", (*spec.Spec).PostgresqlParam.Version)
 | 
						|
 | 
						|
	cluster := &Cluster{
 | 
						|
		config:      cfg,
 | 
						|
		cluster:     spec,
 | 
						|
		logger:      lg,
 | 
						|
		etcdHost:    constants.EtcdHost,
 | 
						|
		dockerImage: dockerImage,
 | 
						|
	}
 | 
						|
	cluster.init()
 | 
						|
 | 
						|
	return cluster
 | 
						|
}
 | 
						|
 | 
						|
func secretUserKey(userName string) string {
 | 
						|
	return fmt.Sprintf("%s-password", userName)
 | 
						|
}
 | 
						|
 | 
						|
func (c *Cluster) init() {
 | 
						|
	for _, userName := range patroniUsers {
 | 
						|
		user := pgUser{
 | 
						|
			username: userName,
 | 
						|
			secretKey: secretUserKey(userName),
 | 
						|
			password: util.RandomPasswordBytes(constants.PasswordLength),
 | 
						|
		}
 | 
						|
		c.pgUsers = append(c.pgUsers, user)
 | 
						|
	}
 | 
						|
 | 
						|
	for userName, userFlags := range (*c.cluster.Spec).Users {
 | 
						|
		user := pgUser{
 | 
						|
			username: userName,
 | 
						|
			secretKey: secretUserKey(userName),
 | 
						|
			password: util.RandomPasswordBytes(constants.PasswordLength),
 | 
						|
			flags: userFlags,
 | 
						|
		}
 | 
						|
	 	c.pgUsers = append(c.pgUsers, user)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (c *Cluster) Create() error {
 | 
						|
	c.createEndPoint()
 | 
						|
	c.createService()
 | 
						|
	c.applySecrets()
 | 
						|
	c.createStatefulSet()
 | 
						|
 | 
						|
	//TODO: wait for "spilo-role" label to appear on each pod
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (c *Cluster) Delete() error {
 | 
						|
	clusterName := (*c.cluster).Metadata.Name
 | 
						|
	nameSpace := c.config.Namespace
 | 
						|
	orphanDependents := false
 | 
						|
	deleteOptions := &v1.DeleteOptions{
 | 
						|
		OrphanDependents: &orphanDependents,
 | 
						|
	}
 | 
						|
 | 
						|
	listOptions := v1.ListOptions{
 | 
						|
		LabelSelector: fmt.Sprintf("%s=%s", "spilo-cluster", clusterName),
 | 
						|
	}
 | 
						|
 | 
						|
	kubeClient := c.config.KubeClient
 | 
						|
 | 
						|
	podList, err := kubeClient.Pods(nameSpace).List(listOptions)
 | 
						|
	if err != nil {
 | 
						|
		c.logger.Errorf("Error: %+v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = kubeClient.StatefulSets(nameSpace).Delete(clusterName, deleteOptions)
 | 
						|
	if err != nil {
 | 
						|
		c.logger.Errorf("Error: %+v", err)
 | 
						|
	}
 | 
						|
	c.logger.Infof("StatefulSet %s.%s has been deleted\n", nameSpace, clusterName)
 | 
						|
 | 
						|
	for _, pod := range podList.Items {
 | 
						|
		err = kubeClient.Pods(nameSpace).Delete(pod.Name, deleteOptions)
 | 
						|
		if err != nil {
 | 
						|
			c.logger.Errorf("Error while deleting Pod %s: %+v", pod.Name, err)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		c.logger.Infof("Pod %s.%s has been deleted\n", pod.Namespace, pod.Name)
 | 
						|
	}
 | 
						|
 | 
						|
	serviceList, err := kubeClient.Services(nameSpace).List(listOptions)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, service := range serviceList.Items {
 | 
						|
		err = kubeClient.Services(nameSpace).Delete(service.Name, deleteOptions)
 | 
						|
		if err != nil {
 | 
						|
			c.logger.Errorf("Error while deleting Service %s: %+v", service.Name, err)
 | 
						|
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		c.logger.Infof("Service %s.%s has been deleted\n", service.Namespace, service.Name)
 | 
						|
	}
 | 
						|
 | 
						|
	err = kubeClient.Secrets(nameSpace).Delete(clusterName, deleteOptions)
 | 
						|
	if err != nil {
 | 
						|
		c.logger.Errorf("Error while deleting Secret %s: %+v", clusterName, err)
 | 
						|
	}
 | 
						|
 | 
						|
	//TODO: delete key from etcd
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |