forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
/
assess_destroy_model.py
executable file
·164 lines (123 loc) · 4.9 KB
/
assess_destroy_model.py
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python
"""Assess if Juju tracks the model when the current model is destroyed."""
from __future__ import print_function
import argparse
import logging
import sys
import subprocess
import json
from deploy_stack import (
BootstrapManager,
)
from utility import (
add_basic_testing_arguments,
configure_logging,
JujuAssertionError,
)
__metaclass__ = type
log = logging.getLogger("assess_destroy_model")
TEST_MODEL = 'test-tmp-env'
def assess_destroy_model(client):
"""Tests if Juju tracks the model properly through deletion.
In normal behavior Juju should drop the current model selection if that
model is destroyed. This will fail if Juju does not drop it's current
selection.
:param client: Jujupy ModelClient object
"""
current_model = get_current_model(client)
controller = get_current_controller(client)
log.info('Current model: {}'.format(current_model))
new_client = add_model(client)
destroy_model(client, new_client)
log.info('Juju successfully dropped its current model. '
'Switching to {} to complete test'.format(current_model))
switch_model(client, current_model, controller)
log.info('SUCCESS')
def add_model(client):
"""Adds a model to the current juju environment then destroys it.
Will raise an exception if the Juju does not deselect the current model.
:param client: Jujupy ModelClient object
"""
log.info('Adding model "{}" to current controller'.format(TEST_MODEL))
new_client = client.add_model(TEST_MODEL)
new_model = get_current_model(new_client)
if new_model == TEST_MODEL:
log.info('Current model and newly added model match')
else:
error = ('Juju failed to switch to new model after creation. '
'Expected {} got {}'.format(TEST_MODEL, new_model))
raise JujuAssertionError(error)
return new_client
def destroy_model(client, new_client):
log.info('Destroying model "{}"'.format(TEST_MODEL))
new_client.destroy_model()
new_model = get_current_model(client)
if new_model:
error = 'Juju failed to unset model after it was destroyed'
raise JujuAssertionError(error)
def switch_model(client, current_model, current_controller):
"""Switches back to the old model.
:param client: Jujupy ModelClient object
:param current_model: String name of initial testing model
:param current_controller: String name of testing controller
"""
client.switch(model=current_model, controller=current_controller)
new_model = get_current_model(client)
if new_model == current_model:
log.info('Current model and switch target match')
else:
error = ('Juju failed to switch back to existing model. '
'Expected {} got {}'.format(TEST_MODEL, new_model))
raise JujuAssertionError(error)
def get_current_controller(client):
"""Gets the current controller from Juju's list-models command.
:param client: Jujupy ModelClient object
:return: String name of current controller
"""
raw = client.get_juju_output('switch', include_e=False).decode('utf-8')
raw = raw.split(':')[0]
return raw
def get_current_model(client):
"""Gets the current model from Juju's list-models command.
:param client: Jujupy ModelClient object
:return: String name of current model
"""
raw = list_models(client)
try:
return raw['current-model']
except KeyError:
log.warning('No model is currently selected.')
return None
def list_models(client):
"""Helper function to get the output of juju's list-models command.
Instead of using 'juju switch' or client.backend.get_active_model() we use
list-models because that was what the bug report this test was generated
around used. It also allows for flexiblity in the future to get more
detailed information about the models that Juju thinks it has
if we need it.
:param client: Jujupy ModelClient object
:return: Dict of list-models command
"""
try:
raw = client.get_juju_output('list-models', '--format', 'json',
include_e=False).decode('utf-8')
except subprocess.CalledProcessError as e:
log.error('Failed to list current models due to error: {}'.format(e))
raise e
return json.loads(raw)
def parse_args(argv):
"""Parse all arguments."""
parser = argparse.ArgumentParser(
description='Test if juju drops selection of the current model '
'when that model is destroyed.')
add_basic_testing_arguments(parser, existing=False)
return parser.parse_args(argv)
def main(argv=None):
args = parse_args(argv)
configure_logging(args.verbose)
bs_manager = BootstrapManager.from_args(args)
with bs_manager.booted_context(args.upload_tools):
assess_destroy_model(bs_manager.client)
return 0
if __name__ == '__main__':
sys.exit(main())