This repository has been archived by the owner on Mar 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
provides.py
285 lines (245 loc) · 8.77 KB
/
provides.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
"""
This is the provides side of the interface layer, for use only by the Azure
integrator charm itself.
The flags that are set by the provides side of this interface are:
* **`endpoint.{endpoint_name}.requested`** This flag is set when there is
a new or updated request by a remote unit for Azure integration features.
The Azure integration charm should then iterate over each request, perform
whatever actions are necessary to satisfy those requests, and then mark
them as complete.
"""
from operator import attrgetter
from charms.reactive import Endpoint
from charms.reactive import when
from charms.reactive import toggle_flag, clear_flag
class AzureIntegrationProvides(Endpoint):
"""
Example usage:
```python
from charms.reactive import when, endpoint_from_flag
from charms import layer
@when('endpoint.azure.requests-pending')
def handle_requests():
azure = endpoint_from_flag('endpoint.azure.requests-pending')
for request in azure.requests:
if request.instance_tags:
layer.azure.tag_instance(
request.vm_name,
request.resource_group,
request.instance_tags)
if request.requested_load_balancer_management:
layer.azure.enable_load_balancer_management(
request.charm,
request.vm_name,
request.resource_group,
)
# ...
azure.mark_completed()
```
"""
@when('endpoint.{endpoint_name}.changed')
def check_requests(self):
toggle_flag(self.expand_name('requests-pending'),
len(self.requests) > 0)
clear_flag(self.expand_name('changed'))
@property
def all_requests(self):
"""
A list of all requests that have been made.
"""
if not hasattr(self, '_all_requests'):
self._all_requests = [
IntegrationRequest(unit)
for unit in self.all_joined_units
]
return self._all_requests
@property
def requests(self):
"""
A list of the new or updated #IntegrationRequests that
have been made.
"""
if not hasattr(self, '_requests'):
is_changed = attrgetter('is_changed')
self._requests = list(filter(is_changed, self.all_requests))
return self._requests
@property
def relation_ids(self):
"""
A list of the IDs of all established relations.
"""
return [relation.relation_id for relation in self.relations]
def get_departed_charms(self):
"""
Get a list of all charms that have had all units depart since the
last time this was called.
"""
joined_charms = {unit.received['charm']
for unit in self.all_joined_units
if unit.received['charm']}
departed_charms = [unit.received['charm']
for unit in self.all_departed_units
if unit.received['charm'] not in joined_charms]
self.all_departed_units.clear()
return departed_charms
def mark_completed(self):
"""
Mark all requests as completed and remove the `requests-pending` flag.
"""
for request in self.requests:
request.mark_completed()
clear_flag(self.expand_name('requests-pending'))
self._requests = []
class IntegrationRequest:
"""
A request for integration from a single remote unit.
"""
def __init__(self, unit):
self._unit = unit
@property
def _to_publish(self):
return self._unit.relation.to_publish
@property
def _completed(self):
return self._to_publish.get('completed', {})
@property
def _requested(self):
return self._unit.received['requested']
@property
def is_changed(self):
"""
Whether this request has changed since the last time it was
marked completed (if ever).
"""
if not all([self.charm, self.vm_id, self.vm_name,
self.resource_group, self._requested]):
return False
return self._completed.get(self.vm_id) != self._requested
def mark_completed(self):
"""
Mark this request as having been completed.
"""
completed = self._completed
completed[self.vm_id] = self._requested
self._to_publish['completed'] = completed # have to explicitly update
def send_additional_metadata(self, resource_group_location,
vnet_name, vnet_resource_group,
subnet_name, security_group_name,
security_group_resource_group,
use_managed_identity=True, aad_client=None,
aad_secret=None, tenant_id=None):
self._to_publish.update({
'resource-group-location': resource_group_location,
'vnet-name': vnet_name,
'vnet-resource-group': vnet_resource_group,
'subnet-name': subnet_name,
'security-group-name': security_group_name,
'security-group-resource-group': security_group_resource_group,
'use-managed-identity': use_managed_identity,
'aad-client': aad_client,
'aad-client-secret': aad_secret,
'tenant-id': tenant_id
})
@property
def relation_id(self):
"""
The ID of the relation for the unit making the request.
"""
return self._unit.relation.relation_id
@property
def unit_name(self):
"""
The name of the unit making the request.
"""
return self._unit.unit_name
@property
def application_name(self):
"""
The name of the application making the request.
"""
return self._unit.application_name
@property
def charm(self):
"""
The charm name reported for this request.
"""
return self._unit.received['charm']
@property
def vm_id(self):
"""
The instance ID reported for this request.
"""
return self._unit.received['vm-id']
@property
def vm_name(self):
"""
The instance name reported for this request.
"""
return self._unit.received['vm-name']
@property
def resource_group(self):
"""
The resource group reported for this request.
"""
return self._unit.received['res-group']
@property
def model_uuid(self):
"""
The UUID of the model containing the application making this request.
"""
return self._unit.received['model-uuid']
@property
def instance_tags(self):
"""
Mapping of tag names to values to apply to this instance.
"""
# uses dict() here to make a copy, just to be safe
return dict(self._unit.received.get('instance-tags', {}))
@property
def requested_instance_inspection(self):
"""
Flag indicating whether the ability to inspect instances was requested.
"""
return bool(self._unit.received['enable-instance-inspection'])
@property
def requested_network_management(self):
"""
Flag indicating whether the ability to manage networking was requested.
"""
return bool(self._unit.received['enable-network-management'])
@property
def requested_loadbalancer_management(self):
"""
Flag indicating whether the ability to manage networking was requested.
"""
return bool(self._unit.received['enable-loadbalancer-management'])
@property
def requested_security_management(self):
"""
Flag indicating whether security management was requested.
"""
return bool(self._unit.received['enable-security-management'])
@property
def requested_block_storage_management(self):
"""
Flag indicating whether block storage management was requested.
"""
return bool(self._unit.received['enable-block-storage-management'])
@property
def requested_dns_management(self):
"""
Flag indicating whether DNS management was requested.
"""
return bool(self._unit.received['enable-dns-management'])
@property
def requested_object_storage_access(self):
"""
Flag indicating whether object storage access was requested.
"""
return bool(self._unit.received['enable-object-storage-access'])
@property
def requested_object_storage_management(self):
"""
Flag indicating whether object storage management was requested.
"""
return bool(self._unit.received['enable-object-storage-management'])