dce4697030eab67eb57517d0d6c9f2d05a44c71b
[osm/N2VC.git] / juju / model.py
1 from .client import watcher
2 from .delta import get_entity_delta
3
4
5 class ModelEntity(object):
6 """An object in the Model tree"""
7
8 def __init__(self, data, model):
9 """Initialize a new entity
10
11 :param data: dict of data from a watcher delta
12 :param model: The model instance in whose object tree this
13 entity resides
14
15 """
16 self.data = data
17 self.model = model
18
19 def __getattr__(self, name):
20 return self.data[name]
21
22
23 class Model(object):
24 def __init__(self, connection):
25 """Instantiate a new connected Model.
26
27 :param connection: `juju.client.connection.Connection` instance
28
29 """
30 self.connection = connection
31 self.observers = set()
32 self.state = dict()
33
34 def add_observer(self, callable_):
35 """Register an "on-model-change" callback
36
37 Once a watch is started (Model.watch() is called), ``callable_``
38 will be called each time the model changes. callable_ should
39 accept the following positional arguments:
40
41 delta - An instance of :class:`juju.delta.EntityDelta`
42 containing the raw delta data recv'd from the Juju
43 websocket.
44
45 old_obj - If the delta modifies an existing object in the model,
46 old_obj will be a copy of that object, as it was before the
47 delta was applied. Will be None if the delta creates a new
48 entity in the model.
49
50 new_obj - A copy of the new or updated object, after the delta
51 is applied. Will be None if the delta removes an entity
52 from the model.
53
54 model - The :class:`Model` itself.
55
56 """
57 self.observers.add(callable_)
58
59 async def watch(self):
60 """Start an asynchronous watch against this model.
61
62 See :meth:`add_observer` to register an onchange callback.
63
64 """
65 allwatcher = watcher.AllWatcher()
66 allwatcher.connect(self.connection)
67 while True:
68 results = await allwatcher.Next()
69 for delta in results.deltas:
70 delta = get_entity_delta(delta)
71 old_obj, new_obj = self._apply_delta(delta)
72 self._notify_observers(delta, old_obj, new_obj)
73
74 def _apply_delta(self, delta):
75 """Apply delta to our model state and return the a copy of the
76 affected object as it was before and after the update, e.g.:
77
78 old_obj, new_obj = self._apply_delta(delta)
79
80 old_obj may be None if the delta is for the creation of a new object,
81 e.g. a new application or unit is deployed.
82
83 new_obj may be if no object was created or updated, or if an object
84 was deleted as a result of the delta being applied.
85
86 """
87 old_obj, new_obj = None, None
88
89 if (delta.entity in self.state and
90 delta.get_id() in self.state[delta.entity]):
91 old_obj = self.state[delta.entity][delta.get_id()]
92 if delta.type == 'remove':
93 del self.state[delta.entity][delta.get_id()]
94 return old_obj, new_obj
95
96 new_obj = self.state.setdefault(delta.entity, {})[delta.get_id()] = (
97 self._create_model_entity(delta))
98
99 return old_obj, new_obj
100
101 def _create_model_entity(self, delta):
102 """Return an object instance representing the entity created or
103 updated by ``delta``
104
105 """
106 entity_class = delta.get_entity_class()
107 return entity_class(delta.data, self)
108
109 def _notify_observers(self, delta, old_obj, new_obj):
110 """Call observing callbacks, notifying them of a change in model state
111
112 :param delta: The raw change from the watcher
113 (:class:`juju.client.overrides.Delta`)
114 :param old_obj: The object in the model that this delta updates.
115 May be None.
116 :param new_obj: The object in the model that is created or updated
117 by applying this delta.
118
119 """
120 for o in self.observers:
121 o(delta, old_obj, new_obj, self)
122
123 def add_machine(
124 self, spec=None, constraints=None, disks=None, series=None,
125 count=1):
126 """Start a new, empty machine and optionally a container, or add a
127 container to a machine.
128
129 :param str spec: Machine specification
130 Examples::
131
132 (None) - starts a new machine
133 'lxc' - starts a new machine with on lxc container
134 'lxc:4' - starts a new lxc container on machine 4
135 'ssh:user@10.10.0.3' - manually provisions a machine with ssh
136 'zone=us-east-1a' - starts a machine in zone us-east-1s on AWS
137 'maas2.name' - acquire machine maas2.name on MAAS
138 :param constraints: Machine constraints
139 :type constraints: :class:`juju.Constraints`
140 :param list disks: List of disk :class:`constraints <juju.Constraints>`
141 :param str series: Series
142 :param int count: Number of machines to deploy
143
144 Supported container types are: lxc, lxd, kvm
145
146 When deploying a container to an existing machine, constraints cannot
147 be used.
148
149 """
150 pass
151 add_machines = add_machine
152
153 def add_relation(self, relation1, relation2):
154 """Add a relation between two services.
155
156 :param str relation1: '<service>[:<relation_name>]'
157 :param str relation2: '<service>[:<relation_name>]'
158
159 """
160 pass
161
162 def add_space(self, name, *cidrs):
163 """Add a new network space.
164
165 Adds a new space with the given name and associates the given
166 (optional) list of existing subnet CIDRs with it.
167
168 :param str name: Name of the space
169 :param \*cidrs: Optional list of existing subnet CIDRs
170
171 """
172 pass
173
174 def add_ssh_key(self, key):
175 """Add a public SSH key to this model.
176
177 :param str key: The public ssh key
178
179 """
180 pass
181 add_ssh_keys = add_ssh_key
182
183 def add_subnet(self, cidr_or_id, space, *zones):
184 """Add an existing subnet to this model.
185
186 :param str cidr_or_id: CIDR or provider ID of the existing subnet
187 :param str space: Network space with which to associate
188 :param str \*zones: Zone(s) in which the subnet resides
189
190 """
191 pass
192
193 def get_backups(self):
194 """Retrieve metadata for backups in this model.
195
196 """
197 pass
198
199 def block(self, *commands):
200 """Add a new block to this model.
201
202 :param str \*commands: The commands to block. Valid values are
203 'all-changes', 'destroy-model', 'remove-object'
204
205 """
206 pass
207
208 def get_blocks(self):
209 """List blocks for this model.
210
211 """
212 pass
213
214 def get_cached_images(self, arch=None, kind=None, series=None):
215 """Return a list of cached OS images.
216
217 :param str arch: Filter by image architecture
218 :param str kind: Filter by image kind, e.g. 'lxd'
219 :param str series: Filter by image series, e.g. 'xenial'
220
221 """
222 pass
223
224 def create_backup(self, note=None, no_download=False):
225 """Create a backup of this model.
226
227 :param str note: A note to store with the backup
228 :param bool no_download: Do not download the backup archive
229 :return str: Path to downloaded archive
230
231 """
232 pass
233
234 def create_storage_pool(self, name, provider_type, **pool_config):
235 """Create or define a storage pool.
236
237 :param str name: Name to give the storage pool
238 :param str provider_type: Pool provider type
239 :param \*\*pool_config: key/value pool configuration pairs
240
241 """
242 pass
243
244 def debug_log(
245 self, no_tail=False, exclude_module=None, include_module=None,
246 include=None, level=None, limit=0, lines=10, replay=False,
247 exclude=None):
248 """Get log messages for this model.
249
250 :param bool no_tail: Stop after returning existing log messages
251 :param list exclude_module: Do not show log messages for these logging
252 modules
253 :param list include_module: Only show log messages for these logging
254 modules
255 :param list include: Only show log messages for these entities
256 :param str level: Log level to show, valid options are 'TRACE',
257 'DEBUG', 'INFO', 'WARNING', 'ERROR,
258 :param int limit: Return this many of the most recent (possibly
259 filtered) lines are shown
260 :param int lines: Yield this many of the most recent lines, and keep
261 yielding
262 :param bool replay: Yield the entire log, and keep yielding
263 :param list exclude: Do not show log messages for these entities
264
265 """
266 pass
267
268 def deploy(
269 self, entity_url, service_name=None, bind=None, budget=None,
270 channel=None, config=None, constraints=None, force=False,
271 num_units=1, plan=None, resource=None, series=None, storage=None,
272 to=None):
273 """Deploy a new service or bundle.
274
275 :param str entity_url: Charm or bundle url
276 :param str service_name: Name to give the service
277 :param dict bind: <charm endpoint>:<network space> pairs
278 :param dict budget: <budget name>:<limit> pairs
279 :param str channel: Charm store channel from which to retrieve
280 the charm or bundle, e.g. 'development'
281 :param dict config: Charm configuration dictionary
282 :param constraints: Service constraints
283 :type constraints: :class:`juju.Constraints`
284 :param bool force: Allow charm to be deployed to a machine running
285 an unsupported series
286 :param int num_units: Number of units to deploy
287 :param str plan: Plan under which to deploy charm
288 :param dict resource: <resource name>:<file path> pairs
289 :param str series: Series on which to deploy
290 :param dict storage: Storage constraints TODO how do these look?
291 :param str to: Placement directive, e.g.::
292
293 '23' - machine 23
294 'lxc:7' - new lxc container on machine 7
295 '24/lxc/3' - lxc container 3 or machine 24
296
297 If None, a new machine is provisioned.
298
299 """
300 pass
301
302 def destroy(self):
303 """Terminate all machines and resources for this model.
304
305 """
306 pass
307
308 def get_backup(self, archive_id):
309 """Download a backup archive file.
310
311 :param str archive_id: The id of the archive to download
312 :return str: Path to the archive file
313
314 """
315 pass
316
317 def enable_ha(
318 self, num_controllers=0, constraints=None, series=None, to=None):
319 """Ensure sufficient controllers exist to provide redundancy.
320
321 :param int num_controllers: Number of controllers to make available
322 :param constraints: Constraints to apply to the controller machines
323 :type constraints: :class:`juju.Constraints`
324 :param str series: Series of the controller machines
325 :param list to: Placement directives for controller machines, e.g.::
326
327 '23' - machine 23
328 'lxc:7' - new lxc container on machine 7
329 '24/lxc/3' - lxc container 3 or machine 24
330
331 If None, a new machine is provisioned.
332
333 """
334 pass
335
336 def get_config(self):
337 """Return the configuration settings for this model.
338
339 """
340 pass
341
342 def get_constraints(self):
343 """Return the machine constraints for this model.
344
345 """
346 pass
347
348 def grant(self, username, acl='read'):
349 """Grant a user access to this model.
350
351 :param str username: Username
352 :param str acl: Access control ('read' or 'write')
353
354 """
355 pass
356
357 def import_ssh_key(self, identity):
358 """Add a public SSH key from a trusted indentity source to this model.
359
360 :param str identity: User identity in the form <lp|gh>:<username>
361
362 """
363 pass
364 import_ssh_keys = import_ssh_key
365
366 def get_machines(self, machine, utc=False):
367 """Return list of machines in this model.
368
369 :param str machine: Machine id, e.g. '0'
370 :param bool utc: Display time as UTC in RFC3339 format
371
372 """
373 pass
374
375 def get_shares(self):
376 """Return list of all users with access to this model.
377
378 """
379 pass
380
381 def get_spaces(self):
382 """Return list of all known spaces, including associated subnets.
383
384 """
385 pass
386
387 def get_ssh_key(self):
388 """Return known SSH keys for this model.
389
390 """
391 pass
392 get_ssh_keys = get_ssh_key
393
394 def get_storage(self, filesystem=False, volume=False):
395 """Return details of storage instances.
396
397 :param bool filesystem: Include filesystem storage
398 :param bool volume: Include volume storage
399
400 """
401 pass
402
403 def get_storage_pools(self, names=None, providers=None):
404 """Return list of storage pools.
405
406 :param list names: Only include pools with these names
407 :param list providers: Only include pools for these providers
408
409 """
410 pass
411
412 def get_subnets(self, space=None, zone=None):
413 """Return list of known subnets.
414
415 :param str space: Only include subnets in this space
416 :param str zone: Only include subnets in this zone
417
418 """
419 pass
420
421 def remove_blocks(self):
422 """Remove all blocks from this model.
423
424 """
425 pass
426
427 def remove_backup(self, backup_id):
428 """Delete a backup.
429
430 :param str backup_id: The id of the backup to remove
431
432 """
433 pass
434
435 def remove_cached_images(self, arch=None, kind=None, series=None):
436 """Remove cached OS images.
437
438 :param str arch: Architecture of the images to remove
439 :param str kind: Image kind to remove, e.g. 'lxd'
440 :param str series: Image series to remove, e.g. 'xenial'
441
442 """
443 pass
444
445 def remove_machine(self, *machine_ids):
446 """Remove a machine from this model.
447
448 :param str \*machine_ids: Ids of the machines to remove
449
450 """
451 pass
452 remove_machines = remove_machine
453
454 def remove_ssh_key(self, *keys):
455 """Remove a public SSH key(s) from this model.
456
457 :param str \*keys: Keys to remove
458
459 """
460 pass
461 remove_ssh_keys = remove_ssh_key
462
463 def restore_backup(
464 self, bootstrap=False, constraints=None, archive=None,
465 backup_id=None, upload_tools=False):
466 """Restore a backup archive to a new controller.
467
468 :param bool bootstrap: Bootstrap a new state machine
469 :param constraints: Model constraints
470 :type constraints: :class:`juju.Constraints`
471 :param str archive: Path to backup archive to restore
472 :param str backup_id: Id of backup to restore
473 :param bool upload_tools: Upload tools if bootstrapping a new machine
474
475 """
476 pass
477
478 def retry_provisioning(self):
479 """Retry provisioning for failed machines.
480
481 """
482 pass
483
484 def revoke(self, username, acl='read'):
485 """Revoke a user's access to this model.
486
487 :param str username: Username to revoke
488 :param str acl: Access control ('read' or 'write')
489
490 """
491 pass
492
493 def run(self, command, timeout=None):
494 """Run command on all machines in this model.
495
496 :param str command: The command to run
497 :param int timeout: Time to wait before command is considered failed
498
499 """
500 pass
501
502 def set_config(self, **config):
503 """Set configuration keys on this model.
504
505 :param \*\*config: Config key/values
506
507 """
508 pass
509
510 def set_constraints(self, constraints):
511 """Set machine constraints on this model.
512
513 :param :class:`juju.Constraints` constraints: Machine constraints
514
515 """
516 pass
517
518 def get_action_output(self, action_uuid, wait=-1):
519 """Get the results of an action by ID.
520
521 :param str action_uuid: Id of the action
522 :param int wait: Time in seconds to wait for action to complete
523
524 """
525 pass
526
527 def get_action_status(self, uuid_or_prefix=None, name=None):
528 """Get the status of all actions, filtered by ID, ID prefix, or action name.
529
530 :param str uuid_or_prefix: Filter by action uuid or prefix
531 :param str name: Filter by action name
532
533 """
534 pass
535
536 def get_budget(self, budget_name):
537 """Get budget usage info.
538
539 :param str budget_name: Name of budget
540
541 """
542 pass
543
544 def get_status(self, filter_=None, utc=False):
545 """Return the status of the model.
546
547 :param str filter_: Service or unit name or wildcard ('*')
548 :param bool utc: Display time as UTC in RFC3339 format
549
550 """
551 pass
552 status = get_status
553
554 def sync_tools(
555 self, all_=False, destination=None, dry_run=False, public=False,
556 source=None, stream=None, version=None):
557 """Copy Juju tools into this model.
558
559 :param bool all_: Copy all versions, not just the latest
560 :param str destination: Path to local destination directory
561 :param bool dry_run: Don't do the actual copy
562 :param bool public: Tools are for a public cloud, so generate mirrors
563 information
564 :param str source: Path to local source directory
565 :param str stream: Simplestreams stream for which to sync metadata
566 :param str version: Copy a specific major.minor version
567
568 """
569 pass
570
571 def unblock(self, *commands):
572 """Unblock an operation that would alter this model.
573
574 :param str \*commands: The commands to unblock. Valid values are
575 'all-changes', 'destroy-model', 'remove-object'
576
577 """
578 pass
579
580 def unset_config(self, *keys):
581 """Unset configuration on this model.
582
583 :param str \*keys: The keys to unset
584
585 """
586 pass
587
588 def upgrade_gui(self):
589 """Upgrade the Juju GUI for this model.
590
591 """
592 pass
593
594 def upgrade_juju(
595 self, dry_run=False, reset_previous_upgrade=False,
596 upload_tools=False, version=None):
597 """Upgrade Juju on all machines in a model.
598
599 :param bool dry_run: Don't do the actual upgrade
600 :param bool reset_previous_upgrade: Clear the previous (incomplete)
601 upgrade status
602 :param bool upload_tools: Upload local version of tools
603 :param str version: Upgrade to a specific version
604
605 """
606 pass
607
608 def upload_backup(self, archive_path):
609 """Store a backup archive remotely in Juju.
610
611 :param str archive_path: Path to local archive
612
613 """
614 pass