juju / python-libjuju

Python library for the Juju API
Apache License 2.0
60 stars 100 forks source link

Cannot deploy bundle with storage #361

Closed davigar15 closed 4 years ago

davigar15 commented 5 years ago

Everytime I deploy an application with storage with libjuju, I'm getting this error:

Traceback (most recent call last):
  File "examples/deploy_k8s.py", line 42, in <module>
    loop.run(main())
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/loop.py", line 38, in run
    raise task.exception()
  File "examples/deploy_k8s.py", line 23, in main
    application = await model.deploy( 'cs:osm' )
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/model.py", line 1286, in deploy
    await handler.execute_plan()
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/model.py", line 1969, in execute_plan
    result = await method(*step.args)
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/model.py", line 2140, in deploy
    num_units=num_units,
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/model.py", line 1415, in _deploy
    result = await app_facade.Deploy([app])
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/client/facade.py", line 420, in wrapper
    reply = await f(*args, **kwargs)
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/client/_client8.py", line 745, in Deploy
    reply = await self.rpc(msg)
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/client/facade.py", line 545, in rpc
    result = await self.connection.rpc(msg, encoder=TypeEncoder)
  File "/home/davigar15/.local/lib/python3.6/site-packages/juju/client/connection.py", line 326, in rpc
    raise errors.JujuAPIError(result)
wallyworld commented 5 years ago

There's not enough in the traceback to help diagnose the issue. Can you provide the args to the API call; was there an error logged server side; what was the actual content of the error raised client side etc. I assume the same deployment can be done via the CLI?

davigar15 commented 5 years ago

Hello @wallyworld, sorry, I will send you more information about the issue.

I've just discovered that this only happens when a a bundle with an application using storage is used. If I deploy an standalone k8s charm using storage, it works fine.

Also, if you do the same with juju cli, instead of libjuju, it will work. This only affects libjuju.

I'm adding the steps to reproduce the error:

  1. Setting up the environment
sudo snap install juju --classic
sudo snap install mcirok8s --classic --channel 1.14/stbale
sudo usermod -a -G microk8s $USER
newgrp microk8s
microk8s.status --wait-ready
microk8s.enable storage dns
juju bootstrap microk8s
juju add-model testing
  1. Bundle (./bundle/bundle.yaml)
    description: K8s bundle with Redis
    bundle: kubernetes
    applications:
    prometheus-k8s:
    charm: 'cs:~charmed-osm/prometheus-k8s'
    scale: 1
    series: kubernetes
    storage:
      database: 100M
  2. Python script
    
    from juju import loop
    from juju.model import Model
    from pathlib import Path
    import logging
    import pdb

async def main(): model = Model() await model.connect() application = await model.deploy(str('local:' / Path(file).absolute().parent / "bundle") ) pdb.set_trace() await model.disconnect()

if name == 'main': logging.basicConfig(level=logging.DEBUG) ws_logger = logging.getLogger('websockets.protocol') ws_logger.setLevel(logging.INFO) loop.run(main())


**Complete log:**

(venv) davigar15@Canonical:~/code/python-libjuju$ python3 examples/deploy_k8s_storage.py DEBUG:asyncio:Using selector: EpollSelector DEBUG:juju.client.connection:Driver connected to juju wss://10.152.183.114:17070/model/daf66827-273a-4c20-8302-23a4c550b234/api DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Admin", "request": "Login", "version": 3, "params": { "auth-tag": "user-admin", "credentials": "c73fdec25704b4c0c23da2260bcc4d14" }, "request-id": 1 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 1, 'response': {'servers': [[{'value': '10.152.183.114', 'type': 'ipv4', 'scope': 'local-cloud', 'port': 17070}]], 'model-tag': 'model-daf66827-273a-4c20-8302-23a4c550b234', 'controller-tag': 'controller-0a672e62-9e0f-43a2-82dd-b4aced4b0080', 'user-info': {'display-name': '', 'identity': 'user-admin', 'controller-access': 'superuser', 'model-access': 'admin'}, 'facades': [{'name': 'Action', 'versions': [2, 3]}, {'name': 'ActionPruner', 'versions': [1]}, {'name': 'Agent', 'versions': [2]}, {'name': 'AgentTools', 'versions': [1]}, {'name': 'AllWatcher', 'versions': [1]}, {'name': 'Annotations', 'versions': [2]}, {'name': 'Application', 'versions': [1, 2, 3, 4, 5, 6, 7, 8, 9]}, {'name': 'ApplicationScaler', 'versions': [1]}, {'name': 'Backups', 'versions': [1, 2]}, {'name': 'Block', 'versions': [2]}, {'name': 'Bundle', 'versions': [1, 2, 3]}, {'name': 'CAASAgent', 'versions': [1]}, {'name': 'CAASFirewaller', 'versions': [1]}, {'name': 'CAASOperator', 'versions': [1]}, {'name': 'CAASOperatorProvisioner', 'versions': [1]}, {'name': 'CAASOperatorUpgrader', 'versions': [1]}, {'name': 'CAASUnitProvisioner', 'versions': [1]}, {'name': 'CharmRevisionUpdater', 'versions': [2]}, {'name': 'Charms', 'versions': [2]}, {'name': 'Cleaner', 'versions': [2]}, {'name': 'Client', 'versions': [1, 2]}, {'name': 'CredentialManager', 'versions': [1]}, {'name': 'CredentialValidator', 'versions': [1, 2]}, {'name': 'CrossModelRelations', 'versions': [1]}, {'name': 'Deployer', 'versions': [1]}, {'name': 'DiskManager', 'versions': [2]}, {'name': 'EntityWatcher', 'versions': [2]}, {'name': 'ExternalControllerUpdater', 'versions': [1]}, {'name': 'FanConfigurer', 'versions': [1]}, {'name': 'FilesystemAttachmentsWatcher', 'versions': [2]}, {'name': 'FirewallRules', 'versions': [1]}, {'name': 'Firewaller', 'versions': [3, 4, 5]}, {'name': 'HighAvailability', 'versions': [2]}, {'name': 'HostKeyReporter', 'versions': [1]}, {'name': 'ImageManager', 'versions': [2]}, {'name': 'ImageMetadata', 'versions': [3]}, {'name': 'InstanceMutater', 'versions': [1, 2]}, {'name': 'InstancePoller', 'versions': [3]}, {'name': 'KeyManager', 'versions': [1]}, {'name': 'KeyUpdater', 'versions': [1]}, {'name': 'LeadershipService', 'versions': [2]}, {'name': 'LifeFlag', 'versions': [1]}, {'name': 'LogForwarding', 'versions': [1]}, {'name': 'Logger', 'versions': [1]}, {'name': 'MachineActions', 'versions': [1]}, {'name': 'MachineManager', 'versions': [2, 3, 4, 5, 6]}, {'name': 'MachineUndertaker', 'versions': [1]}, {'name': 'Machiner', 'versions': [1]}, {'name': 'MeterStatus', 'versions': [1]}, {'name': 'MetricsAdder', 'versions': [2]}, {'name': 'MetricsDebug', 'versions': [2]}, {'name': 'MetricsManager', 'versions': [1]}, {'name': 'MigrationFlag', 'versions': [1]}, {'name': 'MigrationMaster', 'versions': [1]}, {'name': 'MigrationMinion', 'versions': [1]}, {'name': 'MigrationStatusWatcher', 'versions': [1]}, {'name': 'ModelConfig', 'versions': [1, 2]}, {'name': 'ModelGeneration', 'versions': [1, 2]}, {'name': 'ModelUpgrader', 'versions': [1]}, {'name': 'NotifyWatcher', 'versions': [1]}, {'name': 'OfferStatusWatcher', 'versions': [1]}, {'name': 'Payloads', 'versions': [1]}, {'name': 'PayloadsHookContext', 'versions': [1]}, {'name': 'Pinger', 'versions': [1]}, {'name': 'Provisioner', 'versions': [3, 4, 5, 6, 7, 8, 9]}, {'name': 'ProxyUpdater', 'versions': [1, 2]}, {'name': 'Reboot', 'versions': [2]}, {'name': 'RelationStatusWatcher', 'versions': [1]}, {'name': 'RelationUnitsWatcher', 'versions': [1]}, {'name': 'RemoteRelations', 'versions': [1]}, {'name': 'Resources', 'versions': [1]}, {'name': 'ResourcesHookContext', 'versions': [1]}, {'name': 'Resumer', 'versions': [2]}, {'name': 'RetryStrategy', 'versions': [1]}, {'name': 'SSHClient', 'versions': [1, 2]}, {'name': 'Singular', 'versions': [2]}, {'name': 'Spaces', 'versions': [2, 3]}, {'name': 'StatusHistory', 'versions': [2]}, {'name': 'Storage', 'versions': [3, 4, 5, 6]}, {'name': 'StorageProvisioner', 'versions': [3, 4]}, {'name': 'StringsWatcher', 'versions': [1]}, {'name': 'Subnets', 'versions': [2]}, {'name': 'Undertaker', 'versions': [1]}, {'name': 'UnitAssigner', 'versions': [1]}, {'name': 'Uniter', 'versions': [4, 5, 6, 7, 8, 9, 10, 11, 12]}, {'name': 'UpgradeSeries', 'versions': [1]}, {'name': 'UpgradeSteps', 'versions': [1]}, {'name': 'Upgrader', 'versions': [1]}, {'name': 'VolumeAttachmentPlansWatcher', 'versions': [1]}, {'name': 'VolumeAttachmentsWatcher', 'versions': [2]}], 'server-version': '2.6.10'}} DEBUG:juju.model:Starting watcher task DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Pinger", "request": "Ping", "version": 1, "params": {}, "request-id": 2 } DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Client", "request": "WatchAll", "version": 2, "params": {}, "request-id": 3 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 2, 'response': {}} DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 3, 'response': {'watcher-id': '1'}} DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "AllWatcher", "request": "Next", "version": 1, "params": {}, "Id": "1", "request-id": 4 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 4, 'response': {'deltas': []}} DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Client", "request": "ModelInfo", "version": 2, "params": {}, "request-id": 5 } DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "AllWatcher", "request": "Next", "version": 1, "params": {}, "Id": "1", "request-id": 6 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 5, 'response': {'name': 'testing', 'type': 'caas', 'uuid': 'daf66827-273a-4c20-8302-23a4c550b234', 'controller-uuid': 'controller-0a672e62-9e0f-43a2-82dd-b4aced4b0080', 'is-controller': False, 'provider-type': 'kubernetes', 'default-series': 'bionic', 'cloud-tag': 'cloud-microk8s', 'cloud-region': 'localhost', 'cloud-credential-tag': 'cloudcred-microk8s_admin_microk8s', 'owner-tag': 'user-admin', 'life': 'alive', 'status': {'status': '', 'info': '', 'since': None}, 'users': None, 'machines': None, 'sla': {'level': 'unsupported', 'owner': ''}, 'agent-version': '2.6.10'}} DEBUG:juju.model:Got ModelInfo: {'agent_version': , 'cloud_credential_tag': 'cloudcred-microk8s_admin_microk8s', 'cloud_region': 'localhost', 'cloud_tag': 'cloud-microk8s', 'controller_uuid': 'controller-0a672e62-9e0f-43a2-82dd-b4aced4b0080', 'default_series': 'bionic', 'is_controller': False, 'life': 'alive', 'machines': [], 'migration': None, 'name': 'testing', 'owner_tag': 'user-admin', 'provider_type': 'kubernetes', 'sla': <class 'juju.client._definitions.ModelSLAInfo'>({'level': 'unsupported', 'owner': '', 'unknown_fields': {}}), 'status': <class 'juju.client._definitions.EntityStatus'>({'data': None, 'info': '', 'since': None, 'status': '', 'unknownfields': {}}), 'type': 'caas', 'users': [], 'uuid': 'daf66827-273a-4c20-8302-23a4c550b234', 'unknown_fields': {}} DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Bundle", "request": "GetChanges", "version": 3, "params": { "bundleURL": "/home/davigar15/code/python-libjuju/examples/bundle", "yaml": "applications:\n prometheus-k8s:\n charm: cs:~charmed-osm/prometheus-k8s\n scale: 1\n series: kubernetes\n storage: {database: 100M}\nbundle: kubernetes\ndescription: K8s bundle with Redis\n" }, "request-id": 7 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 7, 'response': {'changes': [{'id': 'addCharm-0', 'method': 'addCharm', 'args': ['cs:~charmed-osm/prometheus-k8s', 'kubernetes'], 'requires': []}, {'id': 'deploy-1', 'method': 'deploy', 'args': ['$addCharm-0', 'kubernetes', 'prometheus-k8s', {}, '', {'database': '100M'}, {}, {}, {}, 1], 'requires': ['addCharm-0']}, {'id': 'setAnnotations-2', 'method': 'setAnnotations', 'args': ['$deploy-1', 'application', {'bundleURL': '/home/davigar15/code/python-libjuju/examples/bundle'}], 'requires': ['deploy-1']}]}} INFO:juju.bundle:Applying change: upload charm cs:~charmed-osm/prometheus-k8s for series kubernetes DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.jujucharms.com:443 DEBUG:urllib3.connectionpool:https://api.jujucharms.com:443 "GET /charmstore/v5/~charmed-osm/prometheus-k8s/meta/any HTTP/1.1" 200 42 DEBUG:juju.bundle:Adding cs:~charmed-osm/prometheus-k8s-20 DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Client", "request": "AddCharm", "version": 2, "params": { "channel": null, "force": false, "url": "cs:~charmed-osm/prometheus-k8s-20" }, "request-id": 8 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 6, 'response': {'deltas': [['charm', 'change', {'model-uuid': 'daf66827-273a-4c20-8302-23a4c550b234', 'charm-url': 'cs:~charmed-osm/prometheus-k8s-20', 'charm-version': '', 'life': 'alive', 'profile': None}]]}} DEBUG:juju.model:unknown delta type: charm DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "AllWatcher", "request": "Next", "version": 1, "params": {}, "Id": "1", "request-id": 9 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 9, 'response': {'deltas': [['charm', 'change', {'model-uuid': 'daf66827-273a-4c20-8302-23a4c550b234', 'charm-url': 'cs:~charmed-osm/prometheus-k8s-20', 'charm-version': '82f744f', 'life': 'alive', 'profile': None, 'config': {'advertised-hostname': 'prometheus', 'advertised-port': 9090, 'default-target': '', 'web-subpath': '/'}}]]}} DEBUG:juju.model:unknown delta type: charm DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "AllWatcher", "request": "Next", "version": 1, "params": {}, "Id": "1", "request-id": 10 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 8, 'response': {}} INFO:juju.bundle:Applying change: deploy application prometheus-k8s with 1 unit on kubernetes using $addCharm-0 DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.jujucharms.com:443 DEBUG:urllib3.connectionpool:https://api.jujucharms.com:443 "GET /charmstore/v5/~charmed-osm/prometheus-k8s-20/meta/any?include=bundle-machine-count&include=bundle-metadata&include=bundle-unit-count&include=charm-actions&include=charm-config&include=charm-metadata&include=common-info&include=extra-info&include=owner&include=published&include=resources&include=supported-series&include=terms HTTP/1.1" 200 753 DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Resources", "request": "AddPendingResources", "version": 1, "params": { "tag": "application-prometheus-k8s", "url": "cs:~charmed-osm/prometheus-k8s-20", "resources": [ { "description": "Alpine", "fingerprint": null, "name": "alpine-image", "origin": "store", "path": "", "revision": 16, "size": 0, "type": "oci-image" }, { "description": "Image used for UI pod.", "fingerprint": null, "name": "prometheus-image", "origin": "store", "path": "", "revision": 26, "size": 0, "type": "oci-image" } ] }, "request-id": 11 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 11, 'response': {'pending-ids': ['003d1f69-43bd-40c5-8559-3bacd0a444c9', '2897db23-7300-42f8-8648-7448c3e0fd5c']}} INFO:juju.model:Deploying cs:~charmed-osm/prometheus-k8s-20 DEBUG:juju.client.connection:connection 140377524379944 -> { "type": "Application", "request": "Deploy", "version": 8, "params": { "applications": [ { "application": "prometheus-k8s", "channel": null, "charm-url": "cs:~charmed-osm/prometheus-k8s-20", "config": null, "config-yaml": "prometheus-k8s: {}\n", "constraints": null, "endpoint-bindings": {}, "num-units": 1, "placement": [], "resources": { "alpine-image": "003d1f69-43bd-40c5-8559-3bacd0a444c9", "prometheus-image": "2897db23-7300-42f8-8648-7448c3e0fd5c" }, "series": "kubernetes", "storage": { "database": "100M" } } ] }, "request-id": 12 } DEBUG:juju.client.connection:connection 140377524379944 <- {'request-id': 12, 'error': 'json: cannot unmarshal string into Go struct field ApplicationDeploy.storage of type storage.Constraints', 'response': {}} Traceback (most recent call last): File "examples/deploy_k8s_storage.py", line 19, in loop.run(main()) File "/home/davigar15/code/python-libjuju/juju/loop.py", line 38, in run raise task.exception() File "examples/deploy_k8s_storage.py", line 10, in main application = await model.deploy(str('local:' / Path(file).absolute().parent / "bundle") ) File "/home/davigar15/code/python-libjuju/juju/model.py", line 1375, in deploy await handler.execute_plan() File "/home/davigar15/code/python-libjuju/juju/bundle.py", line 153, in executeplan self.references[step.id] = await change.run(self) File "/home/davigar15/code/python-libjuju/juju/bundle.py", line 334, in run num_units=self.num_units, File "/home/davigar15/code/python-libjuju/juju/model.py", line 1508, in _deploy result = await app_facade.Deploy(applications=[app]) File "/home/davigar15/code/python-libjuju/juju/client/facade.py", line 472, in wrapper reply = await f(*args, **kwargs) File "/home/davigar15/code/python-libjuju/juju/client/_client8.py", line 784, in Deploy reply = await self.rpc(msg) File "/home/davigar15/code/python-libjuju/juju/client/facade.py", line 608, in rpc result = await self.connection.rpc(msg, encoder=TypeEncoder) File "/home/davigar15/code/python-libjuju/juju/client/connection.py", line 455, in rpc raise errors.JujuAPIError(result) juju.errors.JujuAPIError: json: cannot unmarshal string into Go struct field ApplicationDeploy.storage of type storage.Constraints

ycliuhw commented 5 years ago

I think this issue is because libjuju doesn't pre-process the constrains string like Juju CLI does before adding the contraints to the API payload. It's not CaaS related. To fix it, change the bundle to

description: K8s bundle with Redis
bundle: kubernetes
applications:
  prometheus-k8s:
    charm: 'cs:~charmed-osm/prometheus-k8s'
    scale: 1
    series: kubernetes
    storage:
      database: 
          size: 100
davigar15 commented 5 years ago

@ycliuhw Thanks a lot for the response. I'm glad that's something easy to fix.

But I'm getting this error when using your bundle. Any ideas?

DEBUG:juju.client.connection:connection 140030016311080 <- {'request-id': 8, 'error': 'cannot read bundle YAML: cannot unmarshal bundle data: yaml: unmarshal errors:\n  line 7: cannot unmarshal !!map into string', 'response': {}}
Traceback (most recent call last):
  File "examples/deploy_k8s_storage.py", line 19, in <module>
    loop.run(main())
  File "/home/davigar15/code/python-libjuju/juju/loop.py", line 38, in run
    raise task.exception()
  File "examples/deploy_k8s_storage.py", line 10, in main
    application = await model.deploy(str('local:' / Path(__file__).absolute().parent / "bundle2") )
  File "/home/davigar15/code/python-libjuju/juju/model.py", line 1374, in deploy
    await handler.fetch_plan(entity_id)
  File "/home/davigar15/code/python-libjuju/juju/bundle.py", line 140, in fetch_plan
    yaml=yaml.dump(self.bundle))
  File "/home/davigar15/code/python-libjuju/juju/client/facade.py", line 472, in wrapper
    reply = await f(*args, **kwargs)
  File "/home/davigar15/code/python-libjuju/juju/client/_client3.py", line 1314, in GetChanges
    reply = await self.rpc(msg)
  File "/home/davigar15/code/python-libjuju/juju/client/facade.py", line 608, in rpc
    result = await self.connection.rpc(msg, encoder=TypeEncoder)
  File "/home/davigar15/code/python-libjuju/juju/client/connection.py", line 455, in rpc
    raise errors.JujuAPIError(result)
juju.errors.JujuAPIError: cannot read bundle YAML: cannot unmarshal bundle data: yaml: unmarshal errors:
  line 7: cannot unmarshal !!map into string

And also, one more question. Is there any way to make a bundle compatible with the juju client and libjuju?

Thanks a lot!

davigar15 commented 5 years ago

I'm deploying that bundle you said with the juju client, the following error happens too:

juju.errors.JujuAPIError: cannot read bundle YAML: cannot unmarshal bundle data: yaml: unmarshal errors:
  line 7: cannot unmarshal !!map into string

My impression is that the juju api-server expects something like this:

    storage:
      database: 100M

And the libjuju expects:

    storage:
      database: 
          size: 100

Also, this only affects to the bundles. With the applications, something like this works:

    application = await model.deploy(
            'cs:~charmed-osm/prometheus-k8s',
            application_name='prometheus',
            series='kubernetes',
            channel='stable',
            storage={
                'database': {
                    'size': 100
                }
            }
    )
ycliuhw commented 5 years ago

Hi @davigar15 This is a known gap in libjuju(it doesn't preprocess the constraint strings before calling the facade), we will fix it.