forked from juju/plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
juju-kill
executable file
·150 lines (113 loc) · 4.49 KB
/
juju-kill
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python
# vim: ts=4 sw=4 et
# Copyright Canonical Ltd 2014, released under AGPL
import yaml
import time
import sys
from subprocess import check_output
def my_call(args):
print(' '.join(args))
check_output(args)
def status():
return yaml.load(check_output(['juju', 'status']))
def wait_for(f):
while f():
time.sleep(0.5)
def destroy_unit(to_destroy):
my_call(['juju', 'destroy-unit', to_destroy])
def is_alive():
for (name, service) in status().get('services', {}).items():
for uname in service.get('units', {}).keys():
if uname == to_destroy:
return True
return False
wait_for(is_alive)
def destroy_machine(to_destroy):
my_call(['juju', 'destroy-machine', '--force', to_destroy])
def is_alive():
for (mname, machine) in status()['machines'].items():
if mname == to_destroy:
return True
for container in machine.get('containers', {}).keys():
if container == to_destroy:
return True
return False
wait_for(is_alive)
def destroy_service(to_destroy):
my_call(['juju', 'destroy-service', to_destroy])
def reap():
""" Reap juju: destroy any services with no units and any machines that are
not in use (including unused containers). """
st = status()
for (sname, service) in st.get('services').items():
if len(service.get('units', {})) == 0:
# We don't need to wait here, since nothing depends on the service.
destroy_service(sname)
def destroy_if_no_units(machine):
units, machines, _ = find_me(machine)
if len(units) == 0 and len(machines) == 1:
my_call(['juju', 'destroy-machine', '--force', machine])
for (mname, machine) in st.get('machines', {}).items():
for container in machine.get('containers', {}).keys():
destroy_if_no_units(container)
# Never kill the bootstrap node.
if mname != "0":
destroy_if_no_units(mname)
def find_me(thing):
""" Find all of the stuff that needs to be destroyed from the specified
thing. """
my_units = set()
my_machines = set()
my_services = set()
st = status()
for (mname, machine) in st.get('machines', {}).items():
if thing == mname:
my_machines.add(thing)
my_machines.update(machine.get('containers', {}).keys())
for cname in machine.get('containers', {}).keys():
if thing == cname:
my_machines.add(thing)
for (sname, service) in st.get('services', {}).items():
if sname == thing:
my_units.update(service.get('units', {}).keys())
my_services.add(sname)
for (uname, unit) in service.get('units', {}).items():
if uname == thing:
my_units.add(uname)
if 'machine' in unit:
my_machines.add(unit['machine'])
if unit.get('machine', None) == thing:
my_units.add(uname)
# if this is on a container that is on a machine to be destroyed,
# we should destroy it too.
if unit.get('machine', None) in my_machines:
my_units.add(uname)
# if we've decided to destroy all the units, we should destroy the
# service too
service_units = {unit.get('machine', None)
for _, unit in service.get('units', {}).items()}
if len(service_units - my_units) > 0:
my_services.add(sname)
return my_units, my_machines, my_services
if __name__ == '__main__':
if len(sys.argv) > 1:
if sys.argv[1] == '--help':
print("juju kill [thing] [--reap]")
print("where thing is any juju object (service, machine, container, unit).")
print("The plugin will reap all unused machines, services with no units, etc.")
print("--reap will optionally destroy unused things in your environment")
sys.exit()
elif sys.argv[1] == '--description':
print("Destroy a juju object and reap the environment.")
sys.exit()
for thing in sys.argv[1:]:
units, machines, services = find_me(thing)
for unit in units:
destroy_unit(unit)
for machine in machines:
destroy_machine(machine)
for service in services:
destroy_service(service)
if '--reap' in sys.argv:
print("reap()ing...")
reap()