Skip to content

Commit

Permalink
Feat/deploy (#3)
Browse files Browse the repository at this point in the history
* refactor

* duplicate deployments

* fix: linting
  • Loading branch information
Telemaco019 authored Jun 23, 2024
1 parent d38fd73 commit 9b81e3b
Show file tree
Hide file tree
Showing 15 changed files with 485 additions and 163 deletions.
2 changes: 1 addition & 1 deletion kubectl-duplicate/kubectl-duplicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

func main() {
rootCmd := cmd.NewRootCmd(nil)
rootCmd := cmd.NewRootCmd(nil, nil)
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
Expand Down
43 changes: 43 additions & 0 deletions pkg/cmd/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Michele Zanotti <[email protected]>
*
* 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/cmd/flags"
"github.com/telemaco019/duplik8s/pkg/utils"
)

func NewKubeOptions(cmd *cobra.Command, _ []string) (utils.KubeOptions, error) {
var err error

o := utils.KubeOptions{}
o.Kubeconfig, err = cmd.Flags().GetString(flags.KUBECONFIG)
if err != nil {
return o, err
}
o.Kubecontext, err = cmd.Flags().GetString(flags.KUBECONTEXT)
if err != nil {
return o, err
}
o.Namespace, err = cmd.Flags().GetString(flags.NAMESPACE)
if err != nil {
return o, err
}

return o, nil
}
44 changes: 44 additions & 0 deletions pkg/cmd/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2024 Michele Zanotti <[email protected]>
*
* 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/deployments"
"github.com/telemaco019/duplik8s/pkg/utils"
)

func NewDeployCmd(client core.Duplik8sClient) *cobra.Command {
factory := func(opts utils.KubeOptions) (core.Duplik8sClient, error) {
if client == nil {
return deployments.NewClient(opts)
}
return client, nil
}
deployCmd := &cobra.Command{
Use: "deploy",
Short: "Duplicate a Deployment.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
run := newDuplicateCmd(factory, "Select a Deployment")
return run(cmd, args)
},
}
addOverrideFlags(deployCmd)
return deployCmd
}
105 changes: 10 additions & 95 deletions pkg/cmd/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,113 +17,28 @@
package cmd

import (
"fmt"
"github.com/charmbracelet/huh"
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/cmd/flags"
"github.com/telemaco019/duplik8s/pkg/core"
"github.com/telemaco019/duplik8s/pkg/pods"
"github.com/telemaco019/duplik8s/pkg/utils"
)

func NewKubeOptions(cmd *cobra.Command, args []string) (utils.KubeOptions, error) {
var err error

o := utils.KubeOptions{}
o.Kubeconfig, err = cmd.Flags().GetString(flags.KUBECONFIG)
if err != nil {
return o, err
}
o.Kubecontext, err = cmd.Flags().GetString(flags.KUBECONTEXT)
if err != nil {
return o, err
func NewPodCmd(podClient core.Duplik8sClient) *cobra.Command {
factory := func(opts utils.KubeOptions) (core.Duplik8sClient, error) {
if podClient == nil {
return pods.NewClient(opts)
}
return podClient, nil
}
o.Namespace, err = cmd.Flags().GetString(flags.NAMESPACE)
if err != nil {
return o, err
}

return o, nil
}

func NewPodCmd(podClient pods.PodClient) *cobra.Command {
podCmd := &cobra.Command{
Use: "pod",
Short: "Duplicate a Pod.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts, err := NewKubeOptions(cmd, args)
if err != nil {
return err
}
if podClient == nil {
podClient, err = pods.NewClient(opts)
if err != nil {
return err
}
}
if err != nil {
return err
}
cmdOverride, err := cmd.Flags().GetStringSlice(flags.COMMAND_OVERRIDE)
if err != nil {
return err
}
argsOverride, err := cmd.Flags().GetStringSlice(flags.ARGS_OVERRIDE)
if err != nil {
return err
}

// Avoid printing usage information on errors
cmd.SilenceUsage = true
options := pods.PodOverrideOptions{
Command: cmdOverride,
Args: argsOverride,
}

var podName string
if len(args) == 0 {
podName, err = selectPod(podClient, opts.Namespace)
if err != nil {
return err
}
} else {
podName = args[0]
}

return podClient.DuplicatePod(podName, opts.Namespace, options)
run := newDuplicateCmd(factory, "Select a Pod")
return run(cmd, args)
},
}
podCmd.Flags().StringSlice(
flags.COMMAND_OVERRIDE,
[]string{"/bin/sh"},
"Override the command of each container in the Pod.",
)
podCmd.Flags().StringSlice(
flags.ARGS_OVERRIDE,
[]string{"-c", "trap 'exit 0' INT TERM KILL; while true; do sleep 1; done"},
"Override the command of each container in the Pod.",
)

addOverrideFlags(podCmd)
return podCmd
}

func selectPod(client pods.PodClient, namespace string) (string, error) {
availablePods, err := client.ListPods(namespace)
if err != nil {
return "", err
}
if len(availablePods) == 0 {
return "", fmt.Errorf("no Pods found in namespace %q", namespace)
}
options := make([]huh.Option[string], len(availablePods))
for i, p := range availablePods {
options[i] = huh.NewOption(p, p)
}
var selectedPod string
err = huh.NewSelect[string]().
Title(fmt.Sprintf("Select a Pod [%s]", namespace)).
Options(options...).
Value(&selectedPod).
Run()
return selectedPod, err
}
6 changes: 3 additions & 3 deletions pkg/cmd/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func Test_NoPodsAvailable(t *testing.T) {
mocks.ListPodsResult{},
nil,
)
cmd := NewRootCmd(podClient)
cmd := NewRootCmd(podClient, nil)
output, err := test.ExecuteCommand(cmd, "pod")
assert.NotEmpty(t, output)
assert.Error(t, err)
Expand All @@ -40,7 +40,7 @@ func Test_Success(t *testing.T) {
mocks.ListPodsResult{},
nil,
)
cmd := NewRootCmd(podClient)
cmd := NewRootCmd(podClient, nil)
_, err := test.ExecuteCommand(cmd, "pod", "pod-1")
assert.NoError(t, err)
}
Expand All @@ -50,7 +50,7 @@ func Test_DuplicateError(t *testing.T) {
mocks.ListPodsResult{},
fmt.Errorf("error"),
)
cmd := NewRootCmd(podClient)
cmd := NewRootCmd(podClient, nil)
_, err := test.ExecuteCommand(cmd, "pod", "pod-1")
assert.EqualError(t, err, "error")
}
8 changes: 5 additions & 3 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ package cmd

import (
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/pods"
"github.com/telemaco019/duplik8s/pkg/core"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/util/homedir"
"path/filepath"
)

func NewRootCmd(
c pods.PodClient,
podClient core.Duplik8sClient,
deployClient core.Duplik8sClient,
) *cobra.Command {
rootCmd := &cobra.Command{
Use: "kubectl-duplicate",
Expand All @@ -50,7 +51,8 @@ func NewRootCmd(
configFlags.AddFlags(rootCmd.PersistentFlags())

// add subcommands
rootCmd.AddCommand(NewPodCmd(c))
rootCmd.AddCommand(NewPodCmd(podClient))
rootCmd.AddCommand(NewDeployCmd(deployClient))

return rootCmd
}
79 changes: 79 additions & 0 deletions pkg/cmd/shared.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2024 Michele Zanotti <[email protected]>
*
* 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/cmd/flags"
"github.com/telemaco019/duplik8s/pkg/core"
"github.com/telemaco019/duplik8s/pkg/utils"
)

type duplik8sClientFactory func(opts utils.KubeOptions) (core.Duplik8sClient, error)

func newDuplicateCmd(factory duplik8sClientFactory, selectMessage string) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
opts, err := NewKubeOptions(cmd, args)
if err != nil {
return err
}
client, err := factory(opts)
if err != nil {
return err
}
cmdOverride, err := cmd.Flags().GetStringSlice(flags.COMMAND_OVERRIDE)
if err != nil {
return err
}
argsOverride, err := cmd.Flags().GetStringSlice(flags.ARGS_OVERRIDE)
if err != nil {
return err
}

// Avoid printing usage information on errors
cmd.SilenceUsage = true
options := core.PodOverrideOptions{
Command: cmdOverride,
Args: argsOverride,
}

var obj core.DuplicableObject
if len(args) == 0 {
obj, err = utils.SelectItem(client, opts.Namespace, selectMessage)
if err != nil {
return err
}
} else {
obj = core.NewPod(args[0], opts.Namespace)
}

return client.Duplicate(obj, options)
}
}

func addOverrideFlags(cmd *cobra.Command) {
cmd.Flags().StringSlice(
flags.COMMAND_OVERRIDE,
[]string{"/bin/sh"},
"Override the command of each container in the Pod.",
)
cmd.Flags().StringSlice(
flags.ARGS_OVERRIDE,
[]string{"-c", "trap 'exit 0' INT TERM KILL; while true; do sleep 1; done"},
"Override the command of each container in the Pod.",
)
}
22 changes: 22 additions & 0 deletions pkg/core/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2024 Michele Zanotti <[email protected]>
*
* 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 core

type Duplik8sClient interface {
List(namespace string) ([]DuplicableObject, error)
Duplicate(obj DuplicableObject, opts PodOverrideOptions) error
}
Loading

0 comments on commit 9b81e3b

Please sign in to comment.