Skip to content

Commit

Permalink
Merge pull request #9 from stackitcloud/feature/change-namespace
Browse files Browse the repository at this point in the history
Add possibility to change target Namespace
  • Loading branch information
brumhard authored Feb 16, 2022
2 parents 9b06fbb + 1251bf8 commit 052903d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ rename-pvc pvc-name new-pvc-name
Example Output:

```shell
Rename PVC from 'pvc-name' to 'new-pvc-name' in namespace 'default'? (yes or no) yes
Rename PVC from 'pvc-name' in namespace 'default' to 'new-pvc-name' in namespace 'default'? (yes or no) y
New PVC with name 'new-pvc-name' created
ClaimRef of PV 'pvc-2dc982d6-72a0-4e80-b1a6-126b108d2adf' is updated to new PVC 'new-pvc-name'
New PVC 'new-pvc-name' is bound to PV 'pvc-2dc982d6-72a0-4e80-b1a6-126b108d2adf'
Old PVC 'pvc-name' is deleted
```

With the flag `--target-namespace` it is possible to change the namespace of the newly created PVC. `rename-pvc -n test1 --target-namespace test2 pvc-name pvc-name` will create the new PVC in Namespace `test2`.

To select the Namespace and Kubernetes cluster you can use the default `kubectl` flags and environment variables (like `--namespace`, `--kubeconfig` or the `KUBECONFIG` environment variable).
For all options run `--help`.

Expand All @@ -73,6 +75,7 @@ Flags:
-n, --namespace string If present, the namespace scope for this CLI request
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
-s, --server string The address and port of the Kubernetes API server
-N, --target-namespace string Defines in which namespace the new PVC should be created. By default the source PVC's namespace is used.
--tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
--token string Bearer token for authentication to the API server
--user string The name of the kubeconfig user to use
Expand Down
55 changes: 35 additions & 20 deletions pkg/renamepvc/renamepvc.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ type renamePVCOptions struct {
streams genericclioptions.IOStreams
configFlags *genericclioptions.ConfigFlags

confirm bool
confirm bool
oldName string
newName string
sourceNamespace string
targetNamespace string
}

// NewCmdRenamePVC returns the cobra command for the pvc rename
Expand All @@ -56,22 +60,32 @@ Afterwards the old PVC is automatically deleted.`,
Args: cobra.ExactArgs(2), //nolint: gomnd // needs always 2 inputs
SilenceUsage: true,
RunE: func(c *cobra.Command, args []string) error {
return o.run(c.Context(), args[0], args[1])
var err error
o.sourceNamespace, _, err = o.configFlags.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}

if o.targetNamespace == "" {
o.targetNamespace = o.sourceNamespace
}

o.oldName = args[0]
o.newName = args[1]

return o.run(c.Context())
},
}
cmd.Flags().BoolVarP(&o.confirm, "yes", "y", false, "Skips confirmation if flag is set")
cmd.Flags().StringVarP(&o.targetNamespace, "target-namespace", "N", "",
"Defines in which namespace the new PVC should be created. By default the source PVC's namespace is used.")
o.configFlags.AddFlags(cmd.Flags())
return cmd
}

// run manages the workflow for renaming a pvc from oldName to newName
func (o *renamePVCOptions) run(ctx context.Context, oldName, newName string) error {
namespace, _, err := o.configFlags.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}

if err := o.confirmCheck(oldName, newName, namespace); err != nil {
func (o *renamePVCOptions) run(ctx context.Context) error {
if err := o.confirmCheck(); err != nil {
return err
}

Expand All @@ -80,7 +94,7 @@ func (o *renamePVCOptions) run(ctx context.Context, oldName, newName string) err
return err
}

oldPvc, err := k8sClient.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, oldName, metav1.GetOptions{})
oldPvc, err := k8sClient.CoreV1().PersistentVolumeClaims(o.sourceNamespace).Get(ctx, o.oldName, metav1.GetOptions{})
if err != nil {
return err
}
Expand All @@ -90,14 +104,16 @@ func (o *renamePVCOptions) run(ctx context.Context, oldName, newName string) err
return err
}

return o.rename(ctx, k8sClient, oldPvc, newName, namespace)
return o.rename(ctx, k8sClient, oldPvc)
}

func (o renamePVCOptions) confirmCheck(oldName, newName, namespace string) error {
func (o *renamePVCOptions) confirmCheck() error {
if o.confirm {
return nil
}
_, err := fmt.Fprintf(o.streams.Out, "Rename PVC from '%s' to '%s' in namespace '%v'? (yes or no) ", oldName, newName, namespace)
_, err := fmt.Fprintf(o.streams.Out,
"Rename PVC from '%s' in namespace '%s' to '%s' in namespace '%v'? (yes or no) ",
o.oldName, o.sourceNamespace, o.newName, o.targetNamespace)
if err != nil {
return err
}
Expand All @@ -115,7 +131,7 @@ func (o renamePVCOptions) confirmCheck(oldName, newName, namespace string) error
}
}

func (o renamePVCOptions) getK8sClient() (*kubernetes.Clientset, error) {
func (o *renamePVCOptions) getK8sClient() (*kubernetes.Clientset, error) {
config, err := o.configFlags.ToRESTConfig()
if err != nil {
return nil, err
Expand Down Expand Up @@ -163,28 +179,27 @@ func waitUntilPvcIsBound(ctx context.Context, k8sClient *kubernetes.Clientset, p
}

// rename the oldPvc to newName
func (o renamePVCOptions) rename(
func (o *renamePVCOptions) rename(
ctx context.Context,
k8sClient *kubernetes.Clientset,
oldPvc *corev1.PersistentVolumeClaim,
newPvcName,
namespace string,
) error {
// get new pvc with old PVC inputs
newPvc := oldPvc.DeepCopy()
newPvc.Status = corev1.PersistentVolumeClaimStatus{}
newPvc.Name = newPvcName
newPvc.Name = o.newName
newPvc.UID = ""
newPvc.CreationTimestamp = metav1.Now()
newPvc.SelfLink = ""
newPvc.ResourceVersion = ""
newPvc.Namespace = o.targetNamespace

pv, err := k8sClient.CoreV1().PersistentVolumes().Get(ctx, oldPvc.Spec.VolumeName, metav1.GetOptions{})
if err != nil {
return err
}

newPvc, err = k8sClient.CoreV1().PersistentVolumeClaims(namespace).Create(ctx, newPvc, metav1.CreateOptions{})
newPvc, err = k8sClient.CoreV1().PersistentVolumeClaims(o.targetNamespace).Create(ctx, newPvc, metav1.CreateOptions{})
if err != nil {
return err
}
Expand All @@ -210,7 +225,7 @@ func (o renamePVCOptions) rename(
}
_, _ = fmt.Fprintf(o.streams.Out, "New PVC '%s' is bound to PV '%s'\n", newPvc.Name, pv.Name)

err = k8sClient.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, oldPvc.Name, metav1.DeleteOptions{})
err = k8sClient.CoreV1().PersistentVolumeClaims(o.sourceNamespace).Delete(ctx, oldPvc.Name, metav1.DeleteOptions{})
if err != nil {
return err
}
Expand Down

0 comments on commit 052903d

Please sign in to comment.