2 from datetime
import datetime
5 from .client
import client
7 log
= logging
.getLogger(__name__
)
10 class Unit(model
.ModelEntity
):
12 def agent_status(self
):
13 """Returns the current agent status string.
16 return self
.data
['agent-status']['current']
19 def agent_status_since(self
):
20 """Get the time when the `agent_status` was last updated.
23 since
= self
.data
['agent-status']['since']
24 # Juju gives us nanoseconds, but Python only supports microseconds
26 return datetime
.strptime(since
, "%Y-%m-%dT%H:%M:%S.%f")
29 def agent_status_message(self
):
30 """Get the agent status message.
33 return self
.data
['agent-status']['message']
36 def workload_status(self
):
37 """Returns the current workload status string.
40 return self
.data
['workload-status']['current']
43 def workload_status_since(self
):
44 """Get the time when the `workload_status` was last updated.
47 since
= self
.data
['workload-status']['since']
48 # Juju gives us nanoseconds, but Python only supports microseconds
50 return datetime
.strptime(since
, "%Y-%m-%dT%H:%M:%S.%f")
53 def workload_status_message(self
):
54 """Get the workload status message.
57 return self
.data
['workload-status']['message']
61 return 'unit-%s' % self
.name
.replace('/', '-')
63 def add_storage(self
, name
, constraints
=None):
64 """Add unit storage dynamically.
66 :param str name: Storage name, as specified by the charm
67 :param str constraints: Comma-separated list of constraints in the
68 form 'POOL,COUNT,SIZE'
73 def collect_metrics(self
):
74 """Collect metrics on this unit.
79 async def destroy(self
):
83 app_facade
= client
.ApplicationFacade()
84 app_facade
.connect(self
.connection
)
87 'Destroying %s', self
.name
)
89 return await app_facade
.DestroyUnits([self
.name
])
92 def get_resources(self
, details
=False):
93 """Return resources for this unit.
95 :param bool details: Include detailed info about resources used by each
101 def resolved(self
, retry
=False):
102 """Mark unit errors resolved.
104 :param bool retry: Re-execute failed hooks
109 async def run(self
, command
, timeout
=None):
110 """Run command on this unit.
112 :param str command: The command to run
113 :param int timeout: Time to wait before command is considered failed
115 Returns a tuple containing the stdout, stderr, and return code
119 action
= client
.ActionFacade()
120 action
.connect(self
.connection
)
123 'Running `%s` on %s', command
, self
.name
)
125 res
= await action
.Run(
132 return await self
.model
.wait_for_action(res
.results
[0].action
.tag
)
134 async def run_action(self
, action_name
, **params
):
135 """Run an action on this unit.
137 :param str action_name: Name of action to run
138 :param \*\*params: Action parameters
139 :returns: An `juju.action.Action` instance.
141 Note that this only enqueues the action. You will need to call
142 ``action.wait()`` on the resulting `Action` instance if you wish
143 to block until the action is complete.
145 action_facade
= client
.ActionFacade()
146 action_facade
.connect(self
.connection
)
148 log
.debug('Starting action `%s` on %s', action_name
, self
.name
)
150 res
= await action_facade
.Enqueue([client
.Action(
155 action
= res
.results
[0].action
156 error
= res
.results
[0].error
157 if error
and error
.code
== 'not found':
158 raise ValueError('Action `%s` not found on %s' % (action_name
,
161 raise Exception('Unknown action error: %s' % error
.serialize())
162 action_id
= action
.tag
[len('action-'):]
163 log
.debug('Action started as %s', action_id
)
164 # we can't use wait_for_new here because we don't
165 # consistently (ever?) get an "add" delta for the action
166 return await self
.model
._wait
('action', action_id
, None)
169 self
, source_path
, user
=None, destination_path
=None, proxy
=False,
171 """Transfer files to this unit.
173 :param str source_path: Path of file(s) to transfer
174 :param str user: Remote username
175 :param str destination_path: Destination of transferred files on
177 :param bool proxy: Proxy through the Juju API server
178 :param str scp_opts: Additional options to the `scp` command
183 def set_meter_status(self
):
184 """Set the meter status on this unit.
190 self
, command
, user
=None, proxy
=False, ssh_opts
=None):
191 """Execute a command over SSH on this unit.
193 :param str command: Command to execute
194 :param str user: Remote username
195 :param bool proxy: Proxy through the Juju API server
196 :param str ssh_opts: Additional options to the `ssh` command
201 def status_history(self
, num
=20, utc
=False):
202 """Get status history for this unit.
204 :param int num: Size of history backlog
205 :param bool utc: Display time as UTC in RFC3339 format