Skip to content

Commit a6c518f

Browse files
committed
New kismatic volume delete command
1 parent f1f606a commit a6c518f

10 files changed

+198
-3
lines changed
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
- hosts: master[0]
3+
any_errors_fatal: true
4+
name: "Delete Kubernetes Persistent Volume"
5+
become: yes
6+
vars_files:
7+
- group_vars/all.yaml
8+
9+
tasks:
10+
- name: delete Kubernetes PV
11+
command: kubectl delete pv {{ volume_name }} --kubeconfig {{ kubernetes_kubeconfig_path }}

ansible/_volume-delete.yaml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
- hosts: storage
3+
any_errors_fatal: true
4+
name: "Delete Gluster Volume"
5+
become: yes
6+
vars_files:
7+
- group_vars/all.yaml
8+
9+
tasks:
10+
- name: verify volume exists
11+
command: gluster volume list
12+
register: out
13+
failed_when: "'{{ volume_name }}' not in out.stdout"
14+
run_once: true
15+
16+
- name: stop Gluster volume
17+
command: gluster volume stop {{ volume_name }} --mode=script
18+
run_once: true
19+
20+
- name: delete Gluster volume
21+
command: gluster volume delete {{ volume_name }} --mode=script
22+
run_once: true
23+
24+
- name: delete brick directory
25+
file:
26+
path: "{{ volume_mount }}{{ volume_base_dir }}{{ volume_name }}"
27+
state: directory
28+
mode: "{{ volume_mode }}"
29+
state: absent

ansible/volume-delete.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
- include: _persistent-volume-delete.yaml
3+
- include: _volume-delete.yaml

integration/storage.go

+26
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ func createVolume(planFile *os.File, name string, replicationCount int, distribu
116116
return cmd.Run()
117117
}
118118

119+
func deleteVolume(planFile *os.File, name string) error {
120+
cmd := exec.Command("./kismatic", "volume", "delete", "-f", planFile.Name(), name, "--force")
121+
cmd.Stdout = os.Stdout
122+
cmd.Stderr = os.Stderr
123+
return cmd.Run()
124+
}
125+
119126
func standupGlusterCluster(planFile *os.File, nodes []NodeDeets, sshKey string, distro linuxDistro) {
120127
By("Setting up a plan file with storage nodes")
121128
plan := PlanAWS{
@@ -238,5 +245,24 @@ func testStatefulWorkload(nodes provisionedNodes, sshKey string) error {
238245
if err != nil {
239246
return fmt.Errorf("Reader workload failed: %v", err)
240247
}
248+
249+
By("Deleting the storage volume")
250+
err = deleteVolume(plan, "kis-int-test")
251+
if err != nil {
252+
return fmt.Errorf("Failed to delete volume: %v", err)
253+
}
254+
255+
By("Verifying the storage volume was deleted")
256+
err = runViaSSH([]string{"sudo kubectl get pv 2>&1 | grep 'No resources found.'"}, []NodeDeets{nodes.master[0]}, sshKey, 30*time.Second)
257+
if err != nil {
258+
return fmt.Errorf("Error validating the volume was removed: %v", err)
259+
}
260+
261+
By("Creating a storage volume with the same name as a deleted volume")
262+
err = createVolume(plan, "kis-int-test", 2, 1, reclaimPolicy, accessModes)
263+
if err != nil {
264+
return fmt.Errorf("Failed to create volume: %v", err)
265+
}
266+
241267
return nil
242268
}

pkg/cli/fakes_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ func (fe *fakeExecutor) AddVolume(*install.Plan, install.StorageVolume) error {
9292
return nil
9393
}
9494

95+
func (fe *fakeExecutor) DeleteVolume(*install.Plan, string) error {
96+
return nil
97+
}
98+
9599
type fakePKI struct {
96100
called bool
97101
generateCACalled bool

pkg/cli/kismatic.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ more documentation is availble at https://github.com/apprenda/kismatic`,
2222

2323
cmd.AddCommand(NewCmdVersion(buildDate, out))
2424
cmd.AddCommand(NewCmdInstall(in, out))
25-
cmd.AddCommand(NewCmdVolume(out))
25+
cmd.AddCommand(NewCmdVolume(in, out))
2626
cmd.AddCommand(NewCmdIP(out))
2727
cmd.AddCommand(NewCmdDashboard(out))
2828
cmd.AddCommand(NewCmdSSH(out))

pkg/cli/volume.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
// NewCmdVolume returns the storage command
10-
func NewCmdVolume(out io.Writer) *cobra.Command {
10+
func NewCmdVolume(in io.Reader, out io.Writer) *cobra.Command {
1111
var planFile string
1212
cmd := &cobra.Command{
1313
Use: "volume",
@@ -19,5 +19,6 @@ func NewCmdVolume(out io.Writer) *cobra.Command {
1919
addPlanFileFlag(cmd.PersistentFlags(), &planFile)
2020
cmd.AddCommand(NewCmdVolumeAdd(out, &planFile))
2121
cmd.AddCommand(NewCmdVolumeList(out, &planFile))
22+
cmd.AddCommand(NewCmdVolumeDelete(in, out, &planFile))
2223
return cmd
2324
}

pkg/cli/volume_add.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type volumeAddOptions struct {
2828
func NewCmdVolumeAdd(out io.Writer, planFile *string) *cobra.Command {
2929
opts := volumeAddOptions{}
3030
cmd := &cobra.Command{
31-
Use: "add size_in_gigabytes [volume name]",
31+
Use: "add size_in_gigabytes [volume-name]",
3232
Short: "add storage volumes to the Kubernetes cluster",
3333
Long: `Add storage volumes to the Kubernetes cluster.
3434

pkg/cli/volume_delete.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
"strings"
8+
9+
"github.com/apprenda/kismatic/pkg/install"
10+
"github.com/apprenda/kismatic/pkg/util"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
type volumeDeleteOptions struct {
15+
verbose bool
16+
outputFormat string
17+
generatedAssetsDir string
18+
force bool
19+
}
20+
21+
// NewCmdVolumeDelete returns the command for deleting storage volumes
22+
func NewCmdVolumeDelete(in io.Reader, out io.Writer, planFile *string) *cobra.Command {
23+
opts := volumeDeleteOptions{}
24+
cmd := &cobra.Command{
25+
Use: "delete volume-name",
26+
Short: "delete storage volumes",
27+
Long: `Delete storage volumes created by the 'volume add' command.
28+
29+
WARNING all data in the volume will be lost.`,
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
if opts.force == false {
32+
ans, err := util.PromptForString(in, out, "Are you sure you want to delete this volume? All data will be lost", "N", []string{"N", "y"})
33+
if err != nil {
34+
return fmt.Errorf("error getting user response: %v", err)
35+
}
36+
if strings.ToLower(ans) != "y" {
37+
os.Exit(0)
38+
}
39+
}
40+
return doVolumeDelete(out, opts, *planFile, args)
41+
},
42+
}
43+
cmd.Flags().BoolVar(&opts.verbose, "verbose", false, "enable verbose logging")
44+
cmd.Flags().StringVarP(&opts.outputFormat, "output", "o", "simple", `output format (options simple|raw)`)
45+
cmd.Flags().StringVar(&opts.generatedAssetsDir, "generated-assets-dir", "generated", "path to the directory where assets generated during the installation process will be stored")
46+
cmd.Flags().BoolVar(&opts.force, "force", false, `do not prompt`)
47+
return cmd
48+
}
49+
50+
func doVolumeDelete(out io.Writer, opts volumeDeleteOptions, planFile string, args []string) error {
51+
// get volume name and size from arguments
52+
var volumeName string
53+
switch len(args) {
54+
case 1:
55+
volumeName = args[0]
56+
default:
57+
return fmt.Errorf("%d arguments were provided, but add does not support more than 1 arguments", len(args))
58+
}
59+
60+
// setup ansible for execution
61+
planner := &install.FilePlanner{File: planFile}
62+
if !planner.PlanExists() {
63+
return planFileNotFoundErr{filename: planFile}
64+
}
65+
execOpts := install.ExecutorOptions{
66+
OutputFormat: opts.outputFormat,
67+
Verbose: opts.verbose,
68+
// Need to refactor executor code... this will do for now as we don't need the generated assets dir in this command
69+
GeneratedAssetsDirectory: opts.generatedAssetsDir,
70+
}
71+
exec, err := install.NewExecutor(out, out, execOpts)
72+
if err != nil {
73+
return err
74+
}
75+
plan, err := planner.Read()
76+
if err != nil {
77+
return err
78+
}
79+
80+
// Run validation
81+
vopts := &validateOpts{
82+
outputFormat: opts.outputFormat,
83+
verbose: opts.verbose,
84+
planFile: planFile,
85+
skipPreFlight: true,
86+
generatedAssetsDir: opts.generatedAssetsDir,
87+
}
88+
if err := doValidate(out, planner, vopts); err != nil {
89+
return err
90+
}
91+
92+
if err := exec.DeleteVolume(plan, volumeName); err != nil {
93+
return fmt.Errorf("error deleting volume: %v", err)
94+
}
95+
96+
fmt.Fprintln(out)
97+
fmt.Fprintln(out, "Successfully deleted the persistent volume in the kubernetes cluster.")
98+
return nil
99+
}

pkg/install/execute.go

+22
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Executor interface {
3434
AddWorker(*Plan, Node) (*Plan, error)
3535
RunPlay(string, *Plan) error
3636
AddVolume(*Plan, StorageVolume) error
37+
DeleteVolume(*Plan, string) error
3738
UpgradeEtcd2Nodes(plan Plan, nodesToUpgrade []ListableNode) error
3839
UpgradeNodes(plan Plan, nodesToUpgrade []ListableNode, onlineUpgrade bool, maxParallelWorkers int) error
3940
ValidateControlPlane(plan Plan) error
@@ -454,6 +455,27 @@ func (ae *ansibleExecutor) AddVolume(plan *Plan, volume StorageVolume) error {
454455
return ae.execute(t)
455456
}
456457

458+
func (ae *ansibleExecutor) DeleteVolume(plan *Plan, name string) error {
459+
cc, err := ae.buildClusterCatalog(plan)
460+
if err != nil {
461+
return err
462+
}
463+
// Add storage related vars
464+
cc.VolumeName = name
465+
cc.VolumeMount = "/"
466+
467+
t := task{
468+
name: "delete-volume",
469+
playbook: "volume-delete.yaml",
470+
plan: *plan,
471+
inventory: buildInventoryFromPlan(plan),
472+
clusterCatalog: *cc,
473+
explainer: ae.defaultExplainer(),
474+
}
475+
util.PrintHeader(ae.stdout, "Delete Persistent Storage Volume", '=')
476+
return ae.execute(t)
477+
}
478+
457479
func (ae *ansibleExecutor) UpgradeEtcd2Nodes(plan Plan, nodesToUpgrade []ListableNode) error {
458480
for _, nodeToUpgrade := range nodesToUpgrade {
459481
if err := ae.upgradeEtcd2Node(plan, nodeToUpgrade); err != nil {

0 commit comments

Comments
 (0)