'Result': {'$ref': '#/definitions/ActionResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ActionResults)
async def Actions(self, entities):
'WatchForModelConfigChanges': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def ClearReboot(self, entities):
name = 'AgentTools'
version = 1
schema = {'properties': {'UpdateToolsAvailable': {'type': 'object'}}, 'type': 'object'}
-
+
@ReturnMapping(None)
async def UpdateToolsAvailable(self):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AllWatcherNextResults)
async def Next(self):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AllWatcherNextResults)
async def Next(self):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AnnotationsGetResults)
async def Get(self, entities):
'Update': {'properties': {'Params': {'$ref': '#/definitions/ApplicationUpdate'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AddRelationResults)
async def AddRelation(self, endpoints):
'Watch': {'properties': {'Result': {'$ref': '#/definitions/StringsWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def Rescale(self, entities):
'Restore': {'properties': {'Params': {'$ref': '#/definitions/RestoreArgs'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(BackupsMetadataResult)
async def Create(self, notes):
'Result': {'$ref': '#/definitions/ErrorResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(BlockResults)
async def List(self):
'Result': {'$ref': '#/definitions/BundleChangesResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(BundleChangesResults)
async def GetChanges(self, yaml):
'properties': {'UpdateLatestRevisions': {'properties': {'Result': {'$ref': '#/definitions/ErrorResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResult)
async def UpdateLatestRevisions(self):
'Result': {'$ref': '#/definitions/CharmsListResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(CharmInfo)
async def CharmInfo(self, url):
'WatchCleanups': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Cleanup(self):
'WatchAll': {'properties': {'Result': {'$ref': '#/definitions/AllWatcherId'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(APIHostPortsResult)
async def APIHostPorts(self):
'Result': {'$ref': '#/definitions/StringsResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(CloudResults)
async def Cloud(self, entities):
'WatchAllModels': {'properties': {'Result': {'$ref': '#/definitions/AllWatcherId'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(UserModelList)
async def AllModels(self):
'Result': {'$ref': '#/definitions/StringsWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsResult)
async def APIAddresses(self):
'ModelConfig': {'properties': {'Result': {'$ref': '#/definitions/ModelConfigResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AddSubnets(self, subnets):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def SetMachineBlockDevices(self, machine_block_devices):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(EntitiesWatchResult)
async def Next(self):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(MachineStorageIdsWatchResult)
async def Next(self):
'Result': {'$ref': '#/definitions/StringsWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(CloudSpecResults)
async def CloudSpec(self, entities):
'Result': {'$ref': '#/definitions/MongoUpgradeResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ControllersChangeResults)
async def EnableHA(self, specs):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def ReportKeys(self, entity_keys):
'Result': {'$ref': '#/definitions/ListImageResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def DeleteImages(self, images):
'type': 'object'},
'UpdateFromPublishedImages': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def Delete(self, image_ids):
'WatchModelMachines': {'properties': {'Result': {'$ref': '#/definitions/StringsWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(BoolResults)
async def AreManuallyProvisioned(self, entities):
'Result': {'$ref': '#/definitions/StringsResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AddKeys(self, ssh_keys, user):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsResults)
async def AuthorisedKeys(self, entities):
'Result': {'$ref': '#/definitions/ClaimLeadershipBulkResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResult)
async def BlockUntilLeadershipReleased(self, name):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(LifeResults)
async def Life(self, entities):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(LogForwardingGetLastSentResults)
async def GetLastSent(self, ids):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringResults)
async def LoggingConfig(self, entities):
'Result': {'$ref': '#/definitions/StringsWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ActionResults)
async def Actions(self, entities):
'Result': {'$ref': '#/definitions/InstanceTypesResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AddMachinesResults)
async def AddMachines(self, params):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(EntitiesResults)
async def AllMachineRemovals(self, entities):
'WatchAPIHostPorts': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsResult)
async def APIAddresses(self):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(MeterStatusResults)
async def GetMeterStatus(self, entities):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AddMetricBatches(self, batches):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(MetricResults)
async def GetMetrics(self, entities):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def CleanupOldMetrics(self, entities):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(PhaseResults)
async def Phase(self, entities):
'WatchMinionReports': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(SerializedModel)
async def Export(self):
'Watch': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Report(self, migration_id, phase, success):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(MigrationStatus)
async def Next(self):
'Prechecks': {'properties': {'Params': {'$ref': '#/definitions/MigrationModelInfo'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Abort(self, model_tag):
'ModelUnset': {'properties': {'Params': {'$ref': '#/definitions/ModelUnset'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ModelConfigResults)
async def ModelGet(self):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ModelInfo)
async def CreateModel(self, cloud_tag, config, credential, name, owner_tag, region):
version = 1
schema = {'properties': {'Next': {'type': 'object'}, 'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Next(self):
'Result': {'$ref': '#/definitions/EnvListResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(EnvListResults)
async def List(self, patterns):
'Result': {'$ref': '#/definitions/PayloadResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(PayloadResults)
async def List(self, entities):
version = 1
schema = {'properties': {'Ping': {'type': 'object'}, 'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Ping(self):
'WatchModelMachines': {'properties': {'Result': {'$ref': '#/definitions/StringsWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsResult)
async def APIAddresses(self):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ProxyConfigResults)
async def ProxyConfig(self, entities):
'WatchForRebootEvent': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def ClearReboot(self, entities):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(RelationUnitsWatchResult)
async def Next(self):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(RemoteApplicationWatchResult)
async def Next(self):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(RemoteRelationsWatchResult)
async def Next(self):
'Result': {'$ref': '#/definitions/ResourcesResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AddPendingResourcesResult)
async def AddPendingResources(self, addcharmwithauthorization, entity, resources):
'Result': {'$ref': '#/definitions/ResourcesResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ResourcesResult)
async def GetResourceInfo(self, entities):
name = 'Resumer'
version = 2
schema = {'properties': {'ResumeTransactions': {'type': 'object'}}, 'type': 'object'}
-
+
@ReturnMapping(None)
async def ResumeTransactions(self):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(RetryStrategyResults)
async def RetryStrategy(self, entities):
'Result': {'$ref': '#/definitions/SSHPublicKeysResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(SSHAddressesResults)
async def AllAddresses(self, entities):
'Result': {'$ref': '#/definitions/ErrorResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def Claim(self, claims):
'ListSpaces': {'properties': {'Result': {'$ref': '#/definitions/ListSpacesResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def CreateSpaces(self, spaces):
'properties': {'Prune': {'properties': {'Params': {'$ref': '#/definitions/StatusHistoryPruneArgs'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(None)
async def Prune(self, max_history_mb, max_history_time):
'Result': {'$ref': '#/definitions/StorageDetailsResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AddToUnit(self, storages):
'Result': {'$ref': '#/definitions/StringsWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(LifeResults)
async def AttachmentLife(self, ids):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsWatchResult)
async def Next(self):
'Result': {'$ref': '#/definitions/ListSubnetsResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AddSubnets(self, subnets):
'WatchModelResources': {'properties': {'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ModelConfigResult)
async def ModelConfig(self):
'WatchUnitAssignments': {'properties': {'Result': {'$ref': '#/definitions/StringsWatchResult'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(ErrorResults)
async def AssignUnits(self, entities):
'Result': {'$ref': '#/definitions/StringResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(StringsResult)
async def APIAddresses(self):
'Result': {'$ref': '#/definitions/NotifyWatchResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(VersionResults)
async def DesiredVersion(self, entities):
'Result': {'$ref': '#/definitions/UserInfoResults'}},
'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(AddUserResults)
async def AddUser(self, users):
'type': 'object'},
'Stop': {'type': 'object'}},
'type': 'object'}
-
+
@ReturnMapping(MachineStorageIdsWatchResult)
async def Next(self):
reply = await self.rpc(msg)
return reply
-
-
'''Replace auto-generated classes with our own, where necessary.
-
'''
from . import _client
prop = method['properties']
spec = prop.get('Params')
if spec:
- params = _types.get(spec['$ref'])
+ result = _types.get(spec['$ref'])
+ if '$ref' in spec:
+ result = _types.get(spec['$ref'])
+ else:
+ result = SCHEMA_TO_PYTHON[spec['type']]
spec = prop.get('Result')
if spec:
if '$ref' in spec:
credential,
model_name,
owner,
- region,
+ region
)
# Add our ssh key to the model, to work around
])
destroy_model = destroy_models
- def add_user(self, username, display_name=None, acl=None, models=None):
+ async def add_user(self, username, password=None, display_name=None):
"""Add a user to this controller.
:param str username: Username
:param list models: Models to which the user is granted access
"""
- raise NotImplementedError()
-
- def change_user_password(self, username, password):
+ if not display_name:
+ display_name = username
+ user_facade = client.UserManagerFacade()
+ user_facade.connect(self.connection)
+ users = [{'display_name': display_name,
+ 'password': password,
+ 'username': username}]
+ return await user_facade.AddUser(users)
+
+ async def change_user_password(self, username, password):
"""Change the password for a user in this controller.
:param str username: Username
:param str password: New password
"""
- raise NotImplementedError()
+ user_facade = client.UserManagerFacade()
+ user_facade.connect(self.connection)
+ entity = client.EntityPassword(password, tag.user(username))
+ return await user_facade.SetPassword([entity])
- def destroy(self, destroy_all_models=False):
+ async def destroy(self, destroy_all_models=False):
"""Destroy this controller.
:param bool destroy_all_models: Destroy all hosted models in the
controller.
"""
- raise NotImplementedError()
+ controller_facade = client.ControllerFacade()
+ controller_facade.connect(self.connection)
+ return await controller_facade.DestroyController(destroy_all_models)
- def disable_user(self, username):
+ async def disable_user(self, username):
"""Disable a user.
:param str username: Username
"""
- raise NotImplementedError()
+ user_facade = client.UserManagerFacade()
+ user_facade.connect(self.connection)
+ entity = client.Entity(tag.user(username))
+ return await user_facade.DisableUser([entity])
- def enable_user(self):
+ async def enable_user(self, username):
"""Re-enable a previously disabled user.
"""
- raise NotImplementedError()
+ user_facade = client.UserManagerFacade()
+ user_facade.connect(self.connection)
+ entity = client.Entity(tag.user(username))
+ return await user_facade.EnableUser([entity])
def kill(self):
"""Forcibly terminate all machines and other associated resources for
cloud = list(result.clouds.keys())[0] # only lives on one cloud
return tag.untag('cloud-', cloud)
- def get_models(self, all_=False, username=None):
+ async def get_models(self, all_=False, username=None):
"""Return list of available models on this controller.
:param bool all_: List all models, regardless of user accessibilty
:param str username: User for which to list models (admin use only)
"""
- raise NotImplementedError()
+ controller_facade = client.ControllerFacade()
+ controller_facade.connect(self.connection)
+ return await controller_facade.AllModels()
+
def get_payloads(self, *patterns):
"""Return list of known payloads.
"""
raise NotImplementedError()
- def get_user(self, username):
+ async def get_user(self, username, include_disabled=False):
"""Get a user by name.
:param str username: Username
"""
- raise NotImplementedError()
+ client_facade = client.UserManagerFacade()
+ client_facade.connect(self.connection)
+ user = tag.user(username)
+ return await client_facade.UserInfo([client.Entity(user)], include_disabled)
+
+ async def grant(self, username, acl='login'):
+ """Set access level of the given user on the controller
+
+ :param str username: Username
+ :param str acl: Access control ('login', 'add-model' or 'superuser')
+
+ """
+ controller_facade = client.ControllerFacade()
+ controller_facade.connect(self.connection)
+ user = tag.user(username)
+ await self.revoke(username)
+ changes = client.ModifyControllerAccess(acl, 'grant', user)
+ return await controller_facade.ModifyControllerAccess([changes])
+
+ async def revoke(self, username):
+ """Removes all access from a controller
+
+ :param str username: username
+
+ """
+ controller_facade = client.ControllerFacade()
+ controller_facade.connect(self.connection)
+ user = tag.user(username)
+ changes = client.ModifyControllerAccess('login', 'revoke', user)
+ return await controller_facade.ModifyControllerAccess([changes])
import asyncio
+import base64
import collections
+import hashlib
import json
import logging
import os
"""
raise NotImplementedError()
- def add_ssh_key(self, key):
+ async def add_ssh_key(self, user, key):
"""Add a public SSH key to this model.
+ :param str user: The username of the user
:param str key: The public ssh key
"""
- raise NotImplementedError()
+ key_facade = client.KeyManagerFacade()
+ key_facade.connect(self.connection)
+ return await key_facade.AddKeys([key], user)
add_ssh_keys = add_ssh_key
def add_subnet(self, cidr_or_id, space, *zones):
storage=storage,
channel=channel,
num_units=num_units,
- placement=parse_placement(to),
+ placement=parse_placement(to)
)
async def _add_store_resources(self, application, entity_url, entity=None):
num_units=num_units,
resources=resources,
storage=storage,
- placement=placement,
+ placement=placement
)
result = await app_facade.Deploy([app])
raise JujuError('\n'.join(errors))
return await self._wait_for_new('application', application)
- def destroy(self):
+ async def destroy(self):
"""Terminate all machines and resources for this model.
-
+ Is already implemented in controller.py.
"""
raise NotImplementedError()
"""
raise NotImplementedError()
- def grant(self, username, acl='read'):
+ async def grant(self, username, acl='read'):
"""Grant a user access to this model.
:param str username: Username
:param str acl: Access control ('read' or 'write')
"""
- raise NotImplementedError()
+ model_facade = client.ModelManagerFacade()
+ controller_conn = await self.connection.controller()
+ model_facade.connect(controller_conn)
+ user = tag.user(username)
+ model = tag.model(self.info.uuid)
+ changes = client.ModifyModelAccess(acl, 'grant', model, user)
+ await self.revoke(username)
+ return await model_facade.ModifyModelAccess([changes])
def import_ssh_key(self, identity):
"""Add a public SSH key from a trusted indentity source to this model.
raise NotImplementedError()
import_ssh_keys = import_ssh_key
- def get_machines(self, machine, utc=False):
+ async def get_machines(self):
"""Return list of machines in this model.
- :param str machine: Machine id, e.g. '0'
- :param bool utc: Display time as UTC in RFC3339 format
-
"""
- raise NotImplementedError()
+ return list(self.state.machines.keys())
def get_shares(self):
"""Return list of all users with access to this model.
"""
raise NotImplementedError()
- def get_ssh_key(self):
+ async def get_ssh_key(self, raw_ssh=False):
"""Return known SSH keys for this model.
+ :param bool raw_ssh: if True, returns the raw ssh key, else it's fingerprint
"""
- raise NotImplementedError()
+ key_facade = client.KeyManagerFacade()
+ key_facade.connect(self.connection)
+ entity = {'tag': tag.model(self.info.uuid)}
+ entities = client.Entities([entity])
+ return await key_facade.ListKeys(entities, raw_ssh)
get_ssh_keys = get_ssh_key
def get_storage(self, filesystem=False, volume=False):
raise NotImplementedError()
remove_machines = remove_machine
- def remove_ssh_key(self, *keys):
+ async def remove_ssh_key(self, user, key):
"""Remove a public SSH key(s) from this model.
- :param str \*keys: Keys to remove
+ :param str key: Full ssh key
+ :param str user: Juju user to which the key is registered
"""
- raise NotImplementedError()
+ key_facade = client.KeyManagerFacade()
+ key_facade.connect(self.connection)
+ key = base64.b64decode(bytes(key.strip().split()[1].encode('ascii')))
+ key = hashlib.md5(key).hexdigest()
+ key = ':'.join(a+b for a, b in zip(key[::2], key[1::2]))
+ await key_facade.DeleteKeys([key], user)
remove_ssh_keys = remove_ssh_key
def restore_backup(
"""
raise NotImplementedError()
- def revoke(self, username, acl='read'):
+ async def revoke(self, username):
"""Revoke a user's access to this model.
:param str username: Username to revoke
- :param str acl: Access control ('read' or 'write')
"""
- raise NotImplementedError()
+ model_facade = client.ModelManagerFacade()
+ controller_conn = await self.connection.controller()
+ model_facade.connect(controller_conn)
+ user = tag.user(username)
+ model = tag.model(self.info.uuid)
+ changes = client.ModifyModelAccess('read', 'revoke', model, user)
+ return await model_facade.ModifyModelAccess([changes])
def run(self, command, timeout=None):
"""Run command on all machines in this model.
reason='bootstrapped Juju environment required')
+class CleanController():
+ def __init__(self):
+ self.controller = None
+
+ async def __aenter__(self):
+ self.controller = Controller()
+ await self.controller.connect_current()
+ return self.controller
+
+ async def __aexit__(self, exc_type, exc, tb):
+ await self.controller.disconnect()
+
+
class CleanModel():
def __init__(self):
self.controller = None
--- /dev/null
+name: charm
+series: ["xenial"]
+summary: "test"
+description: "test"
+maintainers: ["test"]
--- /dev/null
+import asyncio
+from concurrent.futures import ThreadPoolExecutor
+import pytest
+
+from .. import base
+from juju.controller import Controller
+from juju.errors import JujuAPIError
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_add_user(event_loop):
+ async with base.CleanController() as controller:
+ await controller.add_user('test')
+ result = await controller.get_user('test')
+ res_ser = result.serialize()['results'][0].serialize()
+ assert res_ser['result'] is not None
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_disable_enable_user(event_loop):
+ async with base.CleanController() as controller:
+ await controller.add_user('test-disable')
+ await controller.disable_user('test-disable')
+ result = await controller.get_user('test-disable')
+ res_ser = result.serialize()['results'][0].serialize()
+ assert res_ser['result'].serialize()['disabled'] is True
+ await controller.enable_user('test-disable')
+ result = await controller.get_user('test-disable')
+ res_ser = result.serialize()['results'][0].serialize()
+ assert res_ser['result'].serialize()['disabled'] is False
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_change_user_password(event_loop):
+ async with base.CleanController() as controller:
+ await controller.add_user('test-password')
+ await controller.change_user_password('test-password', 'password')
+ try:
+ con = await controller.connect(controller.connection.endpoint, 'test-password', 'password')
+ result = True
+ except JujuAPIError:
+ result = False
+ assert result is True
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_grant(event_loop):
+ async with base.CleanController() as controller:
+ await controller.add_user('test-grant')
+ await controller.grant('test-grant', 'superuser')
+ result = await controller.get_user('test-grant')
+ result = result.serialize()['results'][0].serialize()['result'].serialize()
+ assert result['access'] == 'superuser'
+ await controller.grant('test-grant', 'login')
+ result = await controller.get_user('test-grant')
+ result = result.serialize()['results'][0].serialize()['result'].serialize()
+ assert result['access'] == 'login'
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_get_models(event_loop):
+ async with base.CleanController() as controller:
+ result = await controller.get_models()
+ assert isinstance(result.serialize()['user-models'], list)
MB = 1
GB = 1024
-
+SSH_KEY = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsYMJGNGG74HAJha3n2CFmWYsOOaORnJK6VqNy86pj0MIpvRXBzFzVy09uPQ66GOQhTEoJHEqE77VMui7+62AcMXT+GG7cFHcnU8XVQsGM6UirCcNyWNysfiEMoAdZScJf/GvoY87tMEszhZIUV37z8PUBx6twIqMdr31W1J0IaPa+sV6FEDadeLaNTvancDcHK1zuKsL39jzAg7+LYjKJfEfrsQP+lj/EQcjtKqlhVS5kzsJVfx8ZEd0xhW5G7N6bCdKNalS8mKCMaBXJpijNQ82AiyqCIDCRrre2To0/i7pTjRiL0U9f9mV3S4NJaQaokR050w/ZLySFf6F7joJT mathijs@Qrama-Mathijs'
@base.bootstrapped
@pytest.mark.asyncio
# ghost will go in to blocked (or error, for older
# charm revs) if the resource is missing
assert ghost.units[0].workload_status == 'active'
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_ssh_key(event_loop):
+ async with base.CleanModel() as model:
+ await model.add_ssh_key('admin', SSH_KEY)
+ result = await model.get_ssh_key(True)
+ result = result.serialize()['results'][0].serialize()['result']
+ assert SSH_KEY in result
+ await model.remove_ssh_key('admin', SSH_KEY)
+ result = await model.get_ssh_key(True)
+ result = result.serialize()['results'][0].serialize()['result']
+ assert result is None
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_get_machines(event_loop):
+ async with base.CleanModel() as model:
+ result = await model.get_machines()
+ assert isinstance(result, list)
+
+
+# @base.bootstrapped
+# @pytest.mark.asyncio
+# async def test_grant(event_loop)
+# async with base.CleanController() as controller:
+# await controller.add_user('test-model-grant')
+# await controller.grant('test-model-grant', 'superuser')
+# async with base.CleanModel() as model:
+# await model.grant('test-model-grant', 'admin')
+# assert model.get_user('test-model-grant')['access'] == 'admin'
+# await model.grant('test-model-grant', 'login')
+# assert model.get_user('test-model-grant')['access'] == 'login'