749 lines
25 KiB
Python
749 lines
25 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership.
|
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
# (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import base64
|
|
|
|
try:
|
|
import simplejson as json
|
|
except Exception:
|
|
import json
|
|
|
|
from libcloud.utils.py3 import httplib, urlparse
|
|
from libcloud.utils.py3 import b
|
|
|
|
from libcloud.common.base import JsonResponse, ConnectionUserAndKey
|
|
|
|
from libcloud.container.base import (Container, ContainerDriver,
|
|
ContainerImage)
|
|
|
|
from libcloud.container.providers import Provider
|
|
from libcloud.container.types import ContainerState
|
|
|
|
VALID_RESPONSE_CODES = [httplib.OK, httplib.ACCEPTED, httplib.CREATED,
|
|
httplib.NO_CONTENT]
|
|
|
|
|
|
class RancherResponse(JsonResponse):
|
|
|
|
def parse_error(self):
|
|
parsed = super(RancherResponse, self).parse_error()
|
|
if 'fieldName' in parsed:
|
|
return "Field %s is %s: %s - %s" % (parsed['fieldName'],
|
|
parsed['code'],
|
|
parsed['message'],
|
|
parsed['detail'])
|
|
else:
|
|
return "%s - %s" % (parsed['message'], parsed['detail'])
|
|
|
|
def success(self):
|
|
return self.status in VALID_RESPONSE_CODES
|
|
|
|
|
|
class RancherException(Exception):
|
|
|
|
def __init__(self, code, message):
|
|
self.code = code
|
|
self.message = message
|
|
self.args = (code, message)
|
|
|
|
def __str__(self):
|
|
return "%s %s" % (self.code, self.message)
|
|
|
|
def __repr__(self):
|
|
return "RancherException %s %s" % (self.code, self.message)
|
|
|
|
|
|
class RancherConnection(ConnectionUserAndKey):
|
|
|
|
responseCls = RancherResponse
|
|
timeout = 30
|
|
|
|
def add_default_headers(self, headers):
|
|
"""
|
|
Add parameters that are necessary for every request
|
|
If user and password are specified, include a base http auth
|
|
header
|
|
"""
|
|
headers['Content-Type'] = 'application/json'
|
|
headers['Accept'] = 'application/json'
|
|
if self.key and self.user_id:
|
|
user_b64 = base64.b64encode(b('%s:%s' % (self.user_id, self.key)))
|
|
headers['Authorization'] = 'Basic %s' % (user_b64.decode('utf-8'))
|
|
return headers
|
|
|
|
|
|
class RancherContainerDriver(ContainerDriver):
|
|
"""
|
|
Driver for Rancher by Rancher Labs.
|
|
|
|
This driver is capable of interacting with the Version 1 API of Rancher.
|
|
It currently does NOT support the Version 2 API.
|
|
|
|
Example:
|
|
|
|
>>> from libcloud.container.providers import get_driver
|
|
>>> from libcloud.container.types import Provider
|
|
|
|
>>> driver = get_driver(Provider.RANCHER)
|
|
>>> connection = driver(key="ACCESS_KEY_HERE",
|
|
secret="SECRET_KEY_HERE", host="172.30.0.100", port=8080)
|
|
|
|
>>> image = ContainerImage("hastebin", "hastebin", "rlister/hastebin",
|
|
"latest", driver=None)
|
|
>>> newcontainer = connection.deploy_container("myawesomepastebin",
|
|
image, environment={"STORAGE_TYPE": "file"})
|
|
|
|
:ivar baseuri: The URL base path to the API.
|
|
:type baseuri: ``str``
|
|
"""
|
|
|
|
type = Provider.RANCHER
|
|
name = 'Rancher'
|
|
website = 'http://rancher.com'
|
|
connectionCls = RancherConnection
|
|
# Holding off on cluster support for now.
|
|
# Only Environment API interaction enabled.
|
|
supports_clusters = False
|
|
# As in the /v1/
|
|
version = '1'
|
|
|
|
def __init__(self, key, secret, secure=True, host='localhost', port=443):
|
|
"""
|
|
Creates a new Rancher Container driver.
|
|
|
|
:param key: API key or username to used (required)
|
|
:type key: ``str``
|
|
|
|
:param secret: Secret password to be used (required)
|
|
:type secret: ``str``
|
|
|
|
:param secure: Whether to use HTTPS or HTTP.
|
|
:type secure: ``bool``
|
|
|
|
:param host: Override hostname used for connections. This can also
|
|
be a full URL string, including scheme, port, and base path.
|
|
:type host: ``str``
|
|
|
|
:param port: Override port used for connections.
|
|
:type port: ``int``
|
|
|
|
:return: A newly initialized driver instance.
|
|
"""
|
|
|
|
# Parse the Given Host
|
|
if '://' not in host and not host.startswith("//"):
|
|
host = '//' + host
|
|
parsed = urlparse.urlparse(host)
|
|
|
|
super(RancherContainerDriver, self).__init__(
|
|
key=key,
|
|
secret=secret,
|
|
secure=False if parsed.scheme == 'http' else secure,
|
|
host=parsed.hostname,
|
|
port=parsed.port if parsed.port else port
|
|
)
|
|
|
|
self.baseuri = parsed.path if parsed.path else "/v%s" % self.version
|
|
|
|
def ex_list_stacks(self):
|
|
"""
|
|
List all Rancher Stacks
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/environment/
|
|
|
|
:rtype: ``list`` of ``dict``
|
|
"""
|
|
|
|
result = self.connection.request(
|
|
"%s/environments" % self.baseuri).object
|
|
return result['data']
|
|
|
|
def ex_deploy_stack(self, name, description=None, docker_compose=None,
|
|
environment=None, external_id=None,
|
|
rancher_compose=None, start=True):
|
|
"""
|
|
Deploy a new stack.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/environment/#create
|
|
|
|
:param name: The desired name of the stack. (required)
|
|
:type name: ``str``
|
|
|
|
:param description: A desired description for the stack.
|
|
:type description: ``str``
|
|
|
|
:param docker_compose: The Docker Compose configuration to use.
|
|
:type docker_compose: ``str``
|
|
|
|
:param environment: Environment K/V specific to this stack.
|
|
:type environment: ``dict``
|
|
|
|
:param external_id: The externalId of the stack.
|
|
:type external_id: ``str``
|
|
|
|
:param rancher_compose: The Rancher Compose configuration for this env.
|
|
:type rancher_compose: ``str``
|
|
|
|
:param start: Whether to start this stack on creation.
|
|
:type start: ``bool``
|
|
|
|
:return: The newly created stack.
|
|
:rtype: ``dict``
|
|
"""
|
|
|
|
payload = {
|
|
"description": description,
|
|
"dockerCompose": docker_compose,
|
|
"environment": environment,
|
|
"externalId": external_id,
|
|
"name": name,
|
|
"rancherCompose": rancher_compose,
|
|
"startOnCreate": start
|
|
}
|
|
data = json.dumps(dict((k, v) for (k, v) in payload.items()
|
|
if v is not None))
|
|
result = self.connection.request('%s/environments' %
|
|
self.baseuri, data=data,
|
|
method='POST').object
|
|
|
|
return result
|
|
|
|
def ex_get_stack(self, env_id):
|
|
"""
|
|
Get a stack by ID
|
|
|
|
:param env_id: The stack to be obtained.
|
|
:type env_id: ``str``
|
|
|
|
:rtype: ``dict``
|
|
"""
|
|
result = self.connection.request("%s/environments/%s" %
|
|
(self.baseuri, env_id)).object
|
|
|
|
return result
|
|
|
|
def ex_search_stacks(self, search_params):
|
|
"""
|
|
Search for stacks matching certain filters
|
|
|
|
i.e. ``{ "name": "awesomestack"}``
|
|
|
|
:param search_params: A collection of search parameters to use.
|
|
:type search_params: ``dict``
|
|
|
|
:rtype: ``list``
|
|
"""
|
|
search_list = []
|
|
for f, v in search_params.items():
|
|
search_list.append(f + '=' + v)
|
|
search_items = '&'.join(search_list)
|
|
result = self.connection.request("%s/environments?%s" % (
|
|
self.baseuri, search_items)).object
|
|
|
|
return result['data']
|
|
|
|
def ex_destroy_stack(self, env_id):
|
|
"""
|
|
Destroy a stack by ID
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/environment/#delete
|
|
|
|
:param env_id: The stack to be destroyed.
|
|
:type env_id: ``str``
|
|
|
|
:return: True if destroy was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request('%s/environments/%s' % (
|
|
self.baseuri, env_id),
|
|
method='DELETE')
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def ex_activate_stack(self, env_id):
|
|
"""
|
|
Activate Services for a stack.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/environment/#activateservices
|
|
|
|
:param env_id: The stack to activate services for.
|
|
:type env_id: ``str``
|
|
|
|
:return: True if activate was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request(
|
|
'%s/environments/%s?action=activateservices' % (
|
|
self.baseuri, env_id), method='POST'
|
|
)
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def ex_deactivate_stack(self, env_id):
|
|
"""
|
|
Deactivate Services for a stack.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/environment/#deactivateservices
|
|
|
|
:param env_id: The stack to deactivate services for.
|
|
:type env_id: ``str``
|
|
|
|
:return: True if deactivate was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
|
|
result = self.connection.request(
|
|
'%s/environments/%s?action=deactivateservices' % (
|
|
self.baseuri, env_id), method='POST'
|
|
)
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def ex_list_services(self):
|
|
"""
|
|
List all Rancher Services
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/service/
|
|
|
|
:rtype: ``list`` of ``dict``
|
|
"""
|
|
|
|
result = self.connection.request("%s/services" % self.baseuri).object
|
|
return result['data']
|
|
|
|
def ex_deploy_service(self, name, image, environment_id,
|
|
start=True, assign_service_ip_address=None,
|
|
service_description=None, external_id=None,
|
|
metadata=None, retain_ip=None, scale=None,
|
|
scale_policy=None, secondary_launch_configs=None,
|
|
selector_container=None, selector_link=None,
|
|
vip=None, **launch_conf):
|
|
"""
|
|
Deploy a Rancher Service under a stack.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/service/#create
|
|
|
|
*Any further configuration passed applies to the ``launchConfig``*
|
|
|
|
:param name: The desired name of the service. (required)
|
|
:type name: ``str``
|
|
|
|
:param image: The Image object to deploy. (required)
|
|
:type image: :class:`libcloud.container.base.ContainerImage`
|
|
|
|
:param environment_id: The stack ID this service is tied to. (required)
|
|
:type environment_id: ``str``
|
|
|
|
:param start: Whether to start the service on creation.
|
|
:type start: ``bool``
|
|
|
|
:param assign_service_ip_address: The IP address to assign the service.
|
|
:type assign_service_ip_address: ``bool``
|
|
|
|
:param service_description: The service description.
|
|
:type service_description: ``str``
|
|
|
|
:param external_id: The externalId for this service.
|
|
:type external_id: ``str``
|
|
|
|
:param metadata: K/V Metadata for this service.
|
|
:type metadata: ``dict``
|
|
|
|
:param retain_ip: Whether this service should retain its IP.
|
|
:type retain_ip: ``bool``
|
|
|
|
:param scale: The scale of containers in this service.
|
|
:type scale: ``int``
|
|
|
|
:param scale_policy: The scaling policy for this service.
|
|
:type scale_policy: ``dict``
|
|
|
|
:param secondary_launch_configs: Secondary container launch configs.
|
|
:type secondary_launch_configs: ``list``
|
|
|
|
:param selector_container: The selectorContainer for this service.
|
|
:type selector_container: ``str``
|
|
|
|
:param selector_link: The selectorLink for this service.
|
|
:type selector_link: ``type``
|
|
|
|
:param vip: The VIP to assign to this service.
|
|
:type vip: ``str``
|
|
|
|
:return: The newly created service.
|
|
:rtype: ``dict``
|
|
"""
|
|
|
|
launch_conf['imageUuid'] = self._degen_image(image),
|
|
|
|
service_payload = {
|
|
"assignServiceIpAddress": assign_service_ip_address,
|
|
"description": service_description,
|
|
"environmentId": environment_id,
|
|
"externalId": external_id,
|
|
"launchConfig": launch_conf,
|
|
"metadata": metadata,
|
|
"name": name,
|
|
"retainIp": retain_ip,
|
|
"scale": scale,
|
|
"scalePolicy": scale_policy,
|
|
"secondary_launch_configs": secondary_launch_configs,
|
|
"selectorContainer": selector_container,
|
|
"selectorLink": selector_link,
|
|
"startOnCreate": start,
|
|
"vip": vip
|
|
}
|
|
|
|
data = json.dumps(dict((k, v) for (k, v) in service_payload.items()
|
|
if v is not None))
|
|
result = self.connection.request('%s/services' % self.baseuri,
|
|
data=data, method='POST').object
|
|
|
|
return result
|
|
|
|
def ex_get_service(self, service_id):
|
|
"""
|
|
Get a service by ID
|
|
|
|
:param service_id: The service_id to be obtained.
|
|
:type service_id: ``str``
|
|
|
|
:rtype: ``dict``
|
|
"""
|
|
result = self.connection.request("%s/services/%s" %
|
|
(self.baseuri, service_id)).object
|
|
|
|
return result
|
|
|
|
def ex_search_services(self, search_params):
|
|
"""
|
|
Search for services matching certain filters
|
|
|
|
i.e. ``{ "name": "awesomesause", "environmentId": "1e2"}``
|
|
|
|
:param search_params: A collection of search parameters to use.
|
|
:type search_params: ``dict``
|
|
|
|
:rtype: ``list``
|
|
"""
|
|
search_list = []
|
|
for f, v in search_params.items():
|
|
search_list.append(f + '=' + v)
|
|
search_items = '&'.join(search_list)
|
|
result = self.connection.request("%s/services?%s" % (
|
|
self.baseuri, search_items)).object
|
|
|
|
return result['data']
|
|
|
|
def ex_destroy_service(self, service_id):
|
|
"""
|
|
Destroy a service by ID
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/service/#delete
|
|
|
|
:param service_id: The service to be destroyed.
|
|
:type service_id: ``str``
|
|
|
|
:return: True if destroy was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request('%s/services/%s' % (self.baseuri,
|
|
service_id), method='DELETE')
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def ex_activate_service(self, service_id):
|
|
"""
|
|
Activate a service.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/service/#activate
|
|
|
|
:param service_id: The service to activate services for.
|
|
:type service_id: ``str``
|
|
|
|
:return: True if activate was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request('%s/services/%s?action=activate' %
|
|
(self.baseuri, service_id),
|
|
method='POST')
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def ex_deactivate_service(self, service_id):
|
|
"""
|
|
Deactivate a service.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/service/#deactivate
|
|
|
|
:param service_id: The service to deactivate services for.
|
|
:type service_id: ``str``
|
|
|
|
:return: True if deactivate was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request('%s/services/%s?action=deactivate' %
|
|
(self.baseuri, service_id),
|
|
method='POST')
|
|
return result.status in VALID_RESPONSE_CODES
|
|
|
|
def list_containers(self):
|
|
"""
|
|
List the deployed containers.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/container/
|
|
|
|
:rtype: ``list`` of :class:`libcloud.container.base.Container`
|
|
"""
|
|
|
|
result = self.connection.request("%s/containers" % self.baseuri).object
|
|
containers = [self._to_container(value) for value in result['data']]
|
|
return containers
|
|
|
|
def deploy_container(self, name, image, parameters=None, start=True,
|
|
**config):
|
|
"""
|
|
Deploy a new container.
|
|
|
|
http://docs.rancher.com/rancher/v1.2/en/api/api-resources/container/#create
|
|
|
|
**The following is the Image format used for ``ContainerImage``**
|
|
|
|
*For a ``imageuuid``*:
|
|
|
|
- ``docker:<hostname>:<port>/<namespace>/<imagename>:<version>``
|
|
|
|
*The following applies*:
|
|
|
|
- ``id`` = ``<imagename>``
|
|
- ``name`` = ``<imagename>``
|
|
- ``path`` = ``<hostname>:<port>/<namespace>/<imagename>``
|
|
- ``version`` = ``<version>``
|
|
|
|
*Any extra configuration can also be passed i.e. "environment"*
|
|
|
|
:param name: The desired name of the container. (required)
|
|
:type name: ``str``
|
|
|
|
:param image: The Image object to deploy. (required)
|
|
:type image: :class:`libcloud.container.base.ContainerImage`
|
|
|
|
:param parameters: Container Image parameters (unused)
|
|
:type parameters: ``str``
|
|
|
|
:param start: Whether to start the container on creation(startOnCreate)
|
|
:type start: ``bool``
|
|
|
|
:rtype: :class:`Container`
|
|
"""
|
|
|
|
payload = {
|
|
"name": name,
|
|
"imageUuid": self._degen_image(image),
|
|
"startOnCreate": start,
|
|
}
|
|
config.update(payload)
|
|
|
|
data = json.dumps(config)
|
|
|
|
result = self.connection.request('%s/containers' % self.baseuri,
|
|
data=data, method='POST').object
|
|
|
|
return self._to_container(result)
|
|
|
|
def get_container(self, con_id):
|
|
"""
|
|
Get a container by ID
|
|
|
|
:param con_id: The ID of the container to get
|
|
:type con_id: ``str``
|
|
|
|
:rtype: :class:`libcloud.container.base.Container`
|
|
"""
|
|
result = self.connection.request("%s/containers/%s" %
|
|
(self.baseuri, con_id)).object
|
|
|
|
return self._to_container(result)
|
|
|
|
def start_container(self, container):
|
|
"""
|
|
Start a container
|
|
|
|
:param container: The container to be started
|
|
:type container: :class:`libcloud.container.base.Container`
|
|
|
|
:return: The container refreshed with current data
|
|
:rtype: :class:`libcloud.container.base.Container`
|
|
"""
|
|
result = self.connection.request('%s/containers/%s?action=start' %
|
|
(self.baseuri, container.id),
|
|
method='POST').object
|
|
|
|
return self._to_container(result)
|
|
|
|
def stop_container(self, container):
|
|
"""
|
|
Stop a container
|
|
|
|
:param container: The container to be stopped
|
|
:type container: :class:`libcloud.container.base.Container`
|
|
|
|
:return: The container refreshed with current data
|
|
:rtype: :class:`libcloud.container.base.Container`
|
|
"""
|
|
result = self.connection.request('%s/containers/%s?action=stop' %
|
|
(self.baseuri, container.id),
|
|
method='POST').object
|
|
|
|
return self._to_container(result)
|
|
|
|
def ex_search_containers(self, search_params):
|
|
"""
|
|
Search for containers matching certain filters
|
|
|
|
i.e. ``{ "imageUuid": "docker:mysql", "state": "running"}``
|
|
|
|
:param search_params: A collection of search parameters to use.
|
|
:type search_params: ``dict``
|
|
|
|
:rtype: ``list``
|
|
"""
|
|
search_list = []
|
|
for f, v in search_params.items():
|
|
search_list.append(f + '=' + v)
|
|
search_items = '&'.join(search_list)
|
|
result = self.connection.request("%s/containers?%s" % (
|
|
self.baseuri, search_items)).object
|
|
|
|
return result['data']
|
|
|
|
def destroy_container(self, container):
|
|
"""
|
|
Remove a container
|
|
|
|
:param container: The container to be destroyed
|
|
:type container: :class:`libcloud.container.base.Container`
|
|
|
|
:return: True if the destroy was successful, False otherwise.
|
|
:rtype: ``bool``
|
|
"""
|
|
result = self.connection.request('%s/containers/%s' % (self.baseuri,
|
|
container.id), method='DELETE').object
|
|
|
|
return self._to_container(result)
|
|
|
|
def _gen_image(self, imageuuid):
|
|
"""
|
|
This function converts a valid Rancher ``imageUuid`` string to a valid
|
|
image object. Only supports docker based images hence `docker:` must
|
|
prefix!!
|
|
|
|
Please see the deploy_container() for details on the format.
|
|
|
|
:param imageuuid: A valid Rancher image string
|
|
i.e. ``docker:rlister/hastebin:8.0``
|
|
:type imageuuid: ``str``
|
|
|
|
:return: Converted ContainerImage object.
|
|
:rtype: :class:`libcloud.container.base.ContainerImage`
|
|
"""
|
|
# Obtain just the name(:version) for parsing
|
|
if '/' not in imageuuid:
|
|
# String looks like `docker:mysql:8.0`
|
|
image_name_version = imageuuid.partition(':')[2]
|
|
else:
|
|
# String looks like `docker:oracle/mysql:8.0`
|
|
image_name_version = imageuuid.rpartition("/")[2]
|
|
# Parse based on ':'
|
|
if ':' in image_name_version:
|
|
version = image_name_version.partition(":")[2]
|
|
id = image_name_version.partition(":")[0]
|
|
name = id
|
|
else:
|
|
version = 'latest'
|
|
id = image_name_version
|
|
name = id
|
|
# Get our path based on if there was a version
|
|
if version != 'latest':
|
|
path = imageuuid.partition(':')[2].rpartition(':')[0]
|
|
else:
|
|
path = imageuuid.partition(':')[2]
|
|
|
|
return ContainerImage(
|
|
id=id,
|
|
name=name,
|
|
path=path,
|
|
version=version,
|
|
driver=self.connection.driver,
|
|
extra={
|
|
"imageUuid": imageuuid
|
|
}
|
|
)
|
|
|
|
def _degen_image(self, image):
|
|
"""
|
|
Take in an image object to break down into an ``imageUuid``
|
|
|
|
:param image:
|
|
:return:
|
|
"""
|
|
|
|
# Only supporting docker atm
|
|
image_type = "docker"
|
|
|
|
if image.version is not None:
|
|
return image_type + ':' + image.path + ':' + image.version
|
|
else:
|
|
return image_type + ':' + image.path
|
|
|
|
def _to_container(self, data):
|
|
"""
|
|
Convert container in proper Container instance object
|
|
** Updating is NOT supported!!
|
|
|
|
:param data: API data about container i.e. result.object
|
|
:return: Proper Container object:
|
|
see http://libcloud.readthedocs.io/en/latest/container/api.html
|
|
|
|
"""
|
|
rancher_state = data['state']
|
|
|
|
# A Removed container is purged after x amt of time.
|
|
# Both of these render the container dead (can't be started later)
|
|
terminate_condition = ["removed", "purged"]
|
|
|
|
if 'running' in rancher_state:
|
|
state = ContainerState.RUNNING
|
|
elif 'stopped' in rancher_state:
|
|
state = ContainerState.STOPPED
|
|
elif 'restarting' in rancher_state:
|
|
state = ContainerState.REBOOTING
|
|
elif 'error' in rancher_state:
|
|
state = ContainerState.ERROR
|
|
elif any(x in rancher_state for x in terminate_condition):
|
|
state = ContainerState.TERMINATED
|
|
elif data['transitioning'] == 'yes':
|
|
# Best we can do for current actions
|
|
state = ContainerState.PENDING
|
|
else:
|
|
state = ContainerState.UNKNOWN
|
|
|
|
# Everything contained in the json response is dumped in extra
|
|
extra = data
|
|
|
|
return Container(
|
|
id=data['id'],
|
|
name=data['name'],
|
|
image=self._gen_image(data['imageUuid']),
|
|
ip_addresses=[data['primaryIpAddress']],
|
|
state=state,
|
|
driver=self.connection.driver,
|
|
extra=extra)
|