Skip to content

Commit

Permalink
duplicate statefulsets (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Telemaco019 authored Jun 24, 2024
1 parent 9b81e3b commit 4917979
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 2 deletions.
1 change: 1 addition & 0 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func NewRootCmd(
// add subcommands
rootCmd.AddCommand(NewPodCmd(podClient))
rootCmd.AddCommand(NewDeployCmd(deployClient))
rootCmd.AddCommand(NewStatefulSetCmd(deployClient))

return rootCmd
}
44 changes: 44 additions & 0 deletions pkg/cmd/statefulset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2024 Michele Zanotti <m.zanotti019@gmail.com>
*
* 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 cmd

import (
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/core"
"github.com/telemaco019/duplik8s/pkg/statefulsets"
"github.com/telemaco019/duplik8s/pkg/utils"
)

func NewStatefulSetCmd(client core.Duplik8sClient) *cobra.Command {
factory := func(opts utils.KubeOptions) (core.Duplik8sClient, error) {
if client == nil {
return statefulsets.NewClient(opts)
}
return client, nil
}
deployCmd := &cobra.Command{
Use: "statefulset",
Short: "Duplicate a StatefulSet.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
run := newDuplicateCmd(factory, "Select a StatefulSet")
return run(cmd, args)
},
}
addOverrideFlags(deployCmd)
return deployCmd
}
13 changes: 11 additions & 2 deletions pkg/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import v1 "k8s.io/api/core/v1"
type DuplicableObjectKind string

const (
KindDeployment DuplicableObjectKind = "Deployment"
KindPod DuplicableObjectKind = "Pod"
KindDeployment DuplicableObjectKind = "Deployment"
KindStatefulSet DuplicableObjectKind = "StatefulSet"
KindPod DuplicableObjectKind = "Pod"
)

type PodOverrideOptions struct {
Expand Down Expand Up @@ -59,3 +60,11 @@ func NewDeployment(name, namespace string) DuplicableObject {
Namespace: namespace,
}
}

func NewStatefulSet(name, namespace string) DuplicableObject {
return DuplicableObject{
Kind: KindStatefulSet,
Name: name,
Namespace: namespace,
}
}
101 changes: 101 additions & 0 deletions pkg/statefulsets/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2024 Michele Zanotti <m.zanotti019@gmail.com>
*
* 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 statefulsets

import (
"context"
"fmt"
"github.com/telemaco019/duplik8s/pkg/core"
"github.com/telemaco019/duplik8s/pkg/pods"
"github.com/telemaco019/duplik8s/pkg/utils"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

type StatefulSetClient struct {
clientset *kubernetes.Clientset
ctx context.Context
}

func NewClient(opts utils.KubeOptions) (*StatefulSetClient, error) {
clientset, err := utils.NewClientset(opts.Kubeconfig, opts.Kubecontext)
if err != nil {
return nil, err
}
return &StatefulSetClient{
clientset: clientset,
ctx: context.Background(),
}, nil
}

func (c *StatefulSetClient) List(namespace string) ([]core.DuplicableObject, error) {
statefulSets, err := c.clientset.AppsV1().StatefulSets(namespace).List(c.ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
var objs []core.DuplicableObject
for _, s := range statefulSets.Items {
objs = append(objs, core.NewStatefulSet(s.Name, s.Namespace))
}
return objs, nil
}

func (c *StatefulSetClient) Duplicate(obj core.DuplicableObject, opts core.PodOverrideOptions) error {
fmt.Printf("duplicating statefulset %s\n", obj.Name)

// fetch the StatefulSet
statefulSet, err := c.clientset.AppsV1().StatefulSets(obj.Namespace).Get(c.ctx, obj.Name, metav1.GetOptions{})
if err != nil {
return err
}
if statefulSet.Labels[core.LABEL_DUPLICATED] == "true" {
return fmt.Errorf("statefulset %s is already duplicated", obj.Name)
}

// create a new StatefulSet and override the spec
newName := fmt.Sprintf("%s-duplik8ted", statefulSet.Name)
newStatefulSet := appsv1.StatefulSet{
TypeMeta: metav1.TypeMeta{
Kind: "StatefulSet",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: newName,
Namespace: statefulSet.Namespace,
Labels: map[string]string{
core.LABEL_DUPLICATED: "true",
},
},
Spec: statefulSet.Spec,
}

// override the spec of the statefulset's pod
configurator := pods.NewConfigurator(c.clientset, opts)
err = configurator.OverrideSpec(c.ctx, obj.Namespace, &newStatefulSet.Spec.Template.Spec)
if err != nil {
return err
}

// create the new statefulset
_, err = c.clientset.AppsV1().StatefulSets(obj.Namespace).Create(c.ctx, &newStatefulSet, metav1.CreateOptions{})
if err != nil {
return err
}
fmt.Printf("statefulset %q duplicated in %q\n", obj.Name, newName)
return nil
}

0 comments on commit 4917979

Please sign in to comment.