forked from LaconicNetwork/kompose
Add support for statefulset controller. (#1452)
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
This commit is contained in:
@@ -496,7 +496,7 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
|
||||
volumesMount = append(volumesMount, TmpVolumesMount...)
|
||||
}
|
||||
|
||||
if pvc != nil {
|
||||
if pvc != nil && opt.Controller != StatefulStateController {
|
||||
// Looping on the slice pvc instead of `*objects = append(*objects, pvc...)`
|
||||
// because the type of objects and pvc is different, but when doing append
|
||||
// one element at a time it gets converted to runtime.Object for objects slice
|
||||
@@ -530,7 +530,9 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
|
||||
template.Spec.Containers[0].VolumeMounts = append(template.Spec.Containers[0].VolumeMounts, volumesMount...)
|
||||
template.Spec.Containers[0].Stdin = service.Stdin
|
||||
template.Spec.Containers[0].TTY = service.Tty
|
||||
template.Spec.Volumes = append(template.Spec.Volumes, volumes...)
|
||||
if opt.Controller != StatefulStateController || opt.Volumes == "configMap" {
|
||||
template.Spec.Volumes = append(template.Spec.Volumes, volumes...)
|
||||
}
|
||||
template.Spec.Affinity = ConfigAffinity(service)
|
||||
// Configure the HealthCheck
|
||||
template.Spec.Containers[0].LivenessProbe = configProbe(service.HealthChecks.Liveness)
|
||||
@@ -637,6 +639,18 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
|
||||
objType.Spec.Strategy.Type = appsv1.RecreateDeploymentStrategyType
|
||||
case *deployapi.DeploymentConfig:
|
||||
objType.Spec.Strategy.Type = deployapi.DeploymentStrategyTypeRecreate
|
||||
case *appsv1.StatefulSet:
|
||||
// embed all PVCs inside the StatefulSet object
|
||||
if opt.Volumes == "configMap" {
|
||||
break
|
||||
}
|
||||
persistentVolumeClaims := make([]api.PersistentVolumeClaim, len(pvc))
|
||||
for i, persistentVolumeClaim := range pvc {
|
||||
persistentVolumeClaims[i] = *persistentVolumeClaim
|
||||
persistentVolumeClaims[i].APIVersion = ""
|
||||
persistentVolumeClaims[i].Kind = ""
|
||||
}
|
||||
objType.Spec.VolumeClaimTemplates = persistentVolumeClaims
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ const (
|
||||
DeploymentController = "deployment"
|
||||
// DaemonSetController is controller type for DaemonSet
|
||||
DaemonSetController = "daemonset"
|
||||
// StatefulStateController is controller type for StatefulSet
|
||||
StatefulStateController = "statefulset"
|
||||
)
|
||||
|
||||
// CheckUnsupportedKey checks if given komposeObject contains
|
||||
@@ -425,6 +427,37 @@ func (k *Kubernetes) InitDS(name string, service kobject.ServiceConfig) *appsv1.
|
||||
return ds
|
||||
}
|
||||
|
||||
func (k *Kubernetes) InitSS(name string, service kobject.ServiceConfig, replicas int) *appsv1.StatefulSet {
|
||||
var podSpec api.PodSpec
|
||||
if len(service.Configs) > 0 {
|
||||
podSpec = k.InitPodSpecWithConfigMap(name, service.Image, service)
|
||||
} else {
|
||||
podSpec = k.InitPodSpec(name, service.Image, service.ImagePullSecret)
|
||||
}
|
||||
rp := int32(replicas)
|
||||
ds := &appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StatefulSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: transformer.ConfigAllLabels(name, &service),
|
||||
},
|
||||
Spec: appsv1.StatefulSetSpec{
|
||||
Replicas: &rp,
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: podSpec,
|
||||
},
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: transformer.ConfigLabels(name),
|
||||
},
|
||||
ServiceName: service.Name,
|
||||
},
|
||||
}
|
||||
return ds
|
||||
}
|
||||
|
||||
func (k *Kubernetes) initIngress(name string, service kobject.ServiceConfig, port int32) *networkingv1.Ingress {
|
||||
hosts := regexp.MustCompile("[ ,]*,[ ,]*").Split(service.ExposeService, -1)
|
||||
|
||||
@@ -1120,6 +1153,10 @@ func (k *Kubernetes) CreateWorkloadAndConfigMapObjects(name string, service kobj
|
||||
objects = append(objects, k.InitDS(name, service))
|
||||
}
|
||||
|
||||
if opt.Controller == StatefulStateController {
|
||||
objects = append(objects, k.InitSS(name, service, replica))
|
||||
}
|
||||
|
||||
if len(service.EnvFile) > 0 {
|
||||
for _, envFile := range service.EnvFile {
|
||||
configMap := k.InitConfigMapForEnv(name, opt, envFile)
|
||||
@@ -1280,7 +1317,6 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
allobjects = append(allobjects, item)
|
||||
}
|
||||
}
|
||||
|
||||
if opt.ServiceGroupMode != "" {
|
||||
log.Debugf("Service group mode is: %s", opt.ServiceGroupMode)
|
||||
komposeObjectToServiceConfigGroupMapping := KomposeObjectToServiceConfigGroupMapping(&komposeObject, opt)
|
||||
@@ -1413,6 +1449,9 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
objects = k.CreateWorkloadAndConfigMapObjects(name, service, opt)
|
||||
}
|
||||
|
||||
if opt.Controller == StatefulStateController {
|
||||
service.ServiceType = "Headless"
|
||||
}
|
||||
k.configKubeServiceAndIngressForService(service, name, &objects)
|
||||
|
||||
err := k.UpdateKubernetesObjects(name, service, opt, &objects)
|
||||
@@ -1449,6 +1488,12 @@ func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*a
|
||||
return errors.Wrap(err, "updateTemplate failed")
|
||||
}
|
||||
updateMeta(&t.ObjectMeta)
|
||||
case *appsv1.StatefulSet:
|
||||
err = updateTemplate(&t.Spec.Template)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "updateTemplate failed")
|
||||
}
|
||||
updateMeta(&t.ObjectMeta)
|
||||
case *deployapi.DeploymentConfig:
|
||||
err = updateTemplate(t.Spec.Template)
|
||||
if err != nil {
|
||||
|
||||
@@ -303,7 +303,9 @@ func TestKomposeConvert(t *testing.T) {
|
||||
// objects generated are deployment, daemonset, ReplicationController, service and pvc
|
||||
"Convert to D, DS, and RC": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true, Replicas: replicas, IsReplicaSetFlag: true}, 7},
|
||||
"Convert to D, DS, and RC with v3 replicas": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true}, 7},
|
||||
// TODO: add more tests
|
||||
// objects generated are statefulset
|
||||
"Convert to SS with replicas ": {newKomposeObject(), kobject.ConvertOptions{Controller: StatefulStateController, Replicas: replicas, IsReplicaSetFlag: true}, 5},
|
||||
"Convert to SS without replicas": {newKomposeObject(), kobject.ConvertOptions{Controller: StatefulStateController}, 5},
|
||||
}
|
||||
|
||||
for name, test := range testCases {
|
||||
@@ -318,7 +320,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
t.Errorf("Expected %d objects returned, got %d", test.expectedNumObjs, len(objs))
|
||||
}
|
||||
|
||||
var foundSVC, foundD, foundDS, foundDC bool
|
||||
var foundSVC, foundD, foundDS, foundDC, foundSS bool
|
||||
name := "app"
|
||||
labels := transformer.ConfigLabels(name)
|
||||
config := test.komposeObject.ServiceConfigs[name]
|
||||
@@ -334,6 +336,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
}
|
||||
foundSVC = true
|
||||
}
|
||||
|
||||
if test.opt.CreateD {
|
||||
if d, ok := obj.(*appsv1.Deployment); ok {
|
||||
if err := checkPodTemplate(config, d.Spec.Template, labelsWithNetwork); err != nil {
|
||||
@@ -426,6 +429,60 @@ func TestKomposeConvert(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if test.opt.Controller == StatefulStateController {
|
||||
if ss, ok := obj.(*appsv1.StatefulSet); ok {
|
||||
if err := checkPodTemplate(config, ss.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, ss.ObjectMeta, name, true); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if test.opt.IsReplicaSetFlag {
|
||||
if (int)(*ss.Spec.Replicas) != replicas {
|
||||
t.Errorf("Expected %d replicas, got %d", replicas, ss.Spec.Replicas)
|
||||
}
|
||||
} else {
|
||||
if (int)(*ss.Spec.Replicas) != newServiceConfig().Replicas {
|
||||
t.Errorf("Expected %d replicas, got %d", newServiceConfig().Replicas, ss.Spec.Replicas)
|
||||
}
|
||||
}
|
||||
foundSS = true
|
||||
}
|
||||
|
||||
if u, ok := obj.(*unstructured.Unstructured); ok {
|
||||
if u.GetKind() == "Statefulset" {
|
||||
u.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Statefulset",
|
||||
})
|
||||
data, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
var d appsv1.Deployment
|
||||
if err := json.Unmarshal(data, &d); err == nil {
|
||||
if err := checkPodTemplate(config, d.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, d.ObjectMeta, name, true); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if test.opt.IsReplicaSetFlag {
|
||||
if (int)(*d.Spec.Replicas) != replicas {
|
||||
t.Errorf("Expected %d replicas, got %d", replicas, d.Spec.Replicas)
|
||||
}
|
||||
} else {
|
||||
if (int)(*d.Spec.Replicas) != newServiceConfig().Replicas {
|
||||
t.Errorf("Expected %d replicas, got %d", newServiceConfig().Replicas, d.Spec.Replicas)
|
||||
}
|
||||
}
|
||||
foundSS = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: k8s & openshift transformer is now separated; either separate the test or combine the transformer
|
||||
if test.opt.CreateDeploymentConfig {
|
||||
if dc, ok := obj.(*deployapi.DeploymentConfig); ok {
|
||||
@@ -455,6 +512,9 @@ func TestKomposeConvert(t *testing.T) {
|
||||
t.Errorf("Expected create Daemon Set: %v, found Daemon Set: %v", test.opt.CreateDS, foundDS)
|
||||
}
|
||||
|
||||
if test.opt.Controller == StatefulStateController && !foundSS {
|
||||
t.Errorf("Expected create StatefulStateController")
|
||||
}
|
||||
if test.opt.CreateDeploymentConfig != foundDC {
|
||||
t.Errorf("Expected create Deployment Config: %v, found Deployment Config: %v", test.opt.CreateDeploymentConfig, foundDC)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user