diff --git a/docs/_static/images/provider_logos/rancher.png b/docs/_static/images/provider_logos/rancher.png new file mode 100644 index 0000000000..82dde39b4c Binary files /dev/null and b/docs/_static/images/provider_logos/rancher.png differ diff --git a/docs/container/drivers/rancher.rst b/docs/container/drivers/rancher.rst new file mode 100644 index 0000000000..c1183974d5 --- /dev/null +++ b/docs/container/drivers/rancher.rst @@ -0,0 +1,72 @@ +Rancher Container Service Documentation +======================================= + +Rancher is a container orchestration platform. + +.. figure:: /_static/images/provider_logos/rancher.png + :align: center + :width: 300 + :target: http://rancher.com/ + +This driver supports the main top-level interactions for handling containers, +services, and stacks in a Rancher Environment. + +Here are some notes around this driver: + +- Does not support user based API credentials, only Environment API + credentials (one env, no cluster support) +- Does not support images other than docker formatted images. ``docker:`` + prefix is forced! +- Images follow a standardized format. See deploy_container docstring! +- ``launchConfig`` options for ``ex_deploy_service`` can all be defined at the + top level then get slipstreamed appropriately. +- Passing your own cert/key of any sort for SSL/TLS is not presently supported. + +To enable API access, obtain an Environment API Key from your Rancher Server +for the specific environment you want to control. + +Instantiating the driver +------------------------ + +.. literalinclude:: /examples/container/rancher/instantiate_driver.py + :language: python + +Deploying a container +--------------------- + +.. literalinclude:: /examples/container/rancher/deploy_container.py + :language: python + +Deploying a service +------------------- + +.. literalinclude:: /examples/container/rancher/deploy_service.py + :language: python + +Deploying a stack +----------------- + +.. literalinclude:: /examples/container/rancher/deploy_stack.py + :language: python + +Searching for a container +------------------------- + +.. literalinclude:: /examples/container/rancher/search_containers.py + :language: python + +API Docs +-------- + +.. autoclass:: libcloud.container.drivers.rancher.RancherContainerDriver + :members: + :inherited-members: + +Contributors +------------ + +For the first version of this driver, Mario Loria of Arroyo Networks wrote most +of the code. He received help from Anthony Shaw, a core libcloud contributor +and Vincent Fiduccia, software architect at Rancher Labs. + +.. _`Rancher`: https://rancher.com/ \ No newline at end of file diff --git a/docs/examples/container/rancher/deploy_container.py b/docs/examples/container/rancher/deploy_container.py new file mode 100644 index 0000000000..d783853521 --- /dev/null +++ b/docs/examples/container/rancher/deploy_container.py @@ -0,0 +1,14 @@ +from libcloud.container.types import Provider +from libcloud.container.providers import get_driver +from libcloud.container.base import ContainerImage + +driver = get_driver(Provider.RANCHER) + +connection = driver("MYRANCHERACCESSKEY", "MYRANCHERSECRETKEY", + host="172.30.0.100", port=8080, secure=False) + +image = ContainerImage("hastebin", "hastebin", "rlister/hastebin", "latest", + driver=None) + +new_container = connection.deploy_container(name="awesomecontainer", + image=image, networkMode="managed") diff --git a/docs/examples/container/rancher/deploy_service.py b/docs/examples/container/rancher/deploy_service.py new file mode 100644 index 0000000000..2df6486434 --- /dev/null +++ b/docs/examples/container/rancher/deploy_service.py @@ -0,0 +1,17 @@ +from libcloud.container.types import Provider +from libcloud.container.providers import get_driver +from libcloud.container.base import ContainerImage + +driver = get_driver(Provider.RANCHER) + +connection = driver("MYRANCHERACCESSKEY", "MYRANCHERSECRETKEY", + host="17.23.66.4", port=443) + +image = ContainerImage("hastebin", "hastebin", "rlister/hastebin", "latest", + driver=None) + +new_service = connection.ex_deploy_service(name="excitingservice", image=image, + environmentid="1e2", + environment={ + "STORAGE_TYPE": "file" + }) diff --git a/docs/examples/container/rancher/deploy_stack.py b/docs/examples/container/rancher/deploy_stack.py new file mode 100644 index 0000000000..222a316a5a --- /dev/null +++ b/docs/examples/container/rancher/deploy_stack.py @@ -0,0 +1,13 @@ +from libcloud.container.types import Provider +from libcloud.container.providers import get_driver + +driver = get_driver(Provider.RANCHER) + +connection = driver("MYRANCHERACCESSKEY", "MYRANCHERSECRETKEY", + host="172.30.0.100", port=8080, secure=False) + +new_stack = connection.ex_deploy_stack(name="GhostBlog", + description="Contains services for the" + "ghost blog.") + +id_of_new_stack = new_stack['id'] diff --git a/docs/examples/container/rancher/instantiate_driver.py b/docs/examples/container/rancher/instantiate_driver.py new file mode 100644 index 0000000000..84725996d9 --- /dev/null +++ b/docs/examples/container/rancher/instantiate_driver.py @@ -0,0 +1,9 @@ +from libcloud.container.types import Provider +from libcloud.container.providers import get_driver + +driver = get_driver(Provider.RANCHER) + +connection = driver("MYRANCHERACCESSKEY", "MYRANCHERSECRETKEY", + host="172.30.0.100", port=8080, secure=False) + +connection.list_containers() diff --git a/docs/examples/container/rancher/search_containers.py b/docs/examples/container/rancher/search_containers.py new file mode 100644 index 0000000000..a41ecc3eeb --- /dev/null +++ b/docs/examples/container/rancher/search_containers.py @@ -0,0 +1,12 @@ +from libcloud.container.types import Provider +from libcloud.container.providers import get_driver + +driver = get_driver(Provider.RANCHER) + +connection = driver("MYRANCHERACCESSKEY", "MYRANCHERSECRETKEY", + host="172.30.22.1", port=8080, secure=False) + +search_results = connection.ex_search_containers( + search_params={"imageUuid": "docker:mysql", "state": "running"}) + +id_of_first_result = search_results[0]['id'] diff --git a/libcloud/container/drivers/rancher.py b/libcloud/container/drivers/rancher.py new file mode 100644 index 0000000000..c0d2f9dfa4 --- /dev/null +++ b/libcloud/container/drivers/rancher.py @@ -0,0 +1,720 @@ +# 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: + import json + +from libcloud.utils.py3 import httplib +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() + 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): + + 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): + """ + Rancher Container driver class. + + 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"}) + + :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. + :type host: ``str`` + + :param port: Override port used for connections. + :type port: ``int`` + + + :return: ``None`` + """ + + if host.startswith('http://'): + secure = False + + super(RancherContainerDriver, self).__init__(key=key, secret=secret, + secure=secure, host=host, + port=port) + + # strip the prefix + prefixes = ['http://', 'https://'] + for prefix in prefixes: + if host.startswith(prefix): + host = host.strip(prefix) + + # We only support environment api keys, meaning none of this: + # self.baseuri = "/v%s/projects/%s" % (self.version, project_id) + self.baseuri = "/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:://:`` + + *The following applies*: + + - ``id`` = ```` + - ``name`` = ```` + - ``path`` = ``://`` + - ``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 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') + if result.status in VALID_RESPONSE_CODES: + return self.get_container(container.id) + else: + raise RancherException(result.status, 'failed to stop container') + + 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') + if result.status in VALID_RESPONSE_CODES: + return self.get_container(container.id) + else: + raise RancherException(result.status, 'failed to stop container') + + 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'] + 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 'removed' or 'purged' in rancher_state: + # A Removed container is purged after x amt of time. + # Both of these render the container dead (can't be started later) + 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) diff --git a/libcloud/container/providers.py b/libcloud/container/providers.py index 16ab58cd4c..a8233829e8 100644 --- a/libcloud/container/providers.py +++ b/libcloud/container/providers.py @@ -28,6 +28,8 @@ ('libcloud.container.drivers.ecs', 'ElasticContainerDriver'), Provider.KUBERNETES: ('libcloud.container.drivers.kubernetes', 'KubernetesContainerDriver'), + Provider.RANCHER: + ('libcloud.container.drivers.rancher', 'RancherContainerDriver'), } diff --git a/libcloud/container/types.py b/libcloud/container/types.py index bddca7ff98..b89fdfd3bc 100644 --- a/libcloud/container/types.py +++ b/libcloud/container/types.py @@ -51,6 +51,7 @@ class Provider(object): ECS = 'ecs' JOYENT = 'joyent' KUBERNETES = 'kubernetes' + RANCHER = 'rancher' class ContainerState(Type): diff --git a/libcloud/test/container/fixtures/rancher/deploy_container.json b/libcloud/test/container/fixtures/rancher/deploy_container.json new file mode 100644 index 0000000000..bfe09633df --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/deploy_container.json @@ -0,0 +1,109 @@ +{ + "id": "1i31", + "type": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers/1i31", + "account": "http://172.30.0.100:8080/v1/containers/1i31/account", + "credentials": "http://172.30.0.100:8080/v1/containers/1i31/credentials", + "healthcheckInstanceHostMaps": "http://172.30.0.100:8080/v1/containers/1i31/healthcheckinstancehostmaps", + "hosts": "http://172.30.0.100:8080/v1/containers/1i31/hosts", + "instanceLabels": "http://172.30.0.100:8080/v1/containers/1i31/instancelabels", + "instanceLinks": "http://172.30.0.100:8080/v1/containers/1i31/instancelinks", + "instances": "http://172.30.0.100:8080/v1/containers/1i31/instances", + "mounts": "http://172.30.0.100:8080/v1/containers/1i31/mounts", + "ports": "http://172.30.0.100:8080/v1/containers/1i31/ports", + "serviceEvents": "http://172.30.0.100:8080/v1/containers/1i31/serviceevents", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/containers/1i31/serviceexposemaps", + "services": "http://172.30.0.100:8080/v1/containers/1i31/services", + "targetInstanceLinks": "http://172.30.0.100:8080/v1/containers/1i31/targetinstancelinks", + "volumes": "http://172.30.0.100:8080/v1/containers/1i31/volumes", + "stats": "http://172.30.0.100:8080/v1/containers/1i31/stats", + "containerStats": "http://172.30.0.100:8080/v1/containers/1i31/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/containers/1i31/?action=update", + "error": "http://172.30.0.100:8080/v1/containers/1i31/?action=error", + "remove": "http://172.30.0.100:8080/v1/containers/1i31/?action=remove", + "start": "http://172.30.0.100:8080/v1/containers/1i31/?action=start", + "logs": "http://172.30.0.100:8080/v1/containers/1i31/?action=logs", + "setlabels": "http://172.30.0.100:8080/v1/containers/1i31/?action=setlabels" + }, + "name": "newcontainer", + "state": "running", + "accountId": "1a5", + "blkioDeviceOptions": null, + "build": null, + "capAdd": null, + "capDrop": null, + "command": null, + "cpuSet": null, + "cpuShares": null, + "createIndex": null, + "created": "2016-10-06T15:55:58Z", + "createdTS": 1475769358000, + "dataVolumeMounts": {}, + "dataVolumes": [], + "dataVolumesFrom": null, + "deploymentUnitUuid": null, + "description": null, + "devices": null, + "dns": [ + "169.254.169.250" + ], + "dnsSearch": [ + "rancher.internal" + ], + "dockerPorts": [], + "domainName": null, + "entryPoint": null, + "environment": { + "STORAGE_TYPE": "file" + }, + "expose": null, + "externalId": "ab334bd25d25db7b94fdcead8f5c023b05bed424f56243187aa90f5ef7f07b09", + "extraHosts": null, + "firstRunning": "2016-10-06T15:56:00Z", + "firstRunningTS": 1475769360000, + "healthCheck": null, + "healthState": null, + "hostId": "1h1", + "hostname": null, + "imageUuid": "docker:rlister/hastebin:latest", + "kind": "container", + "labels": { + "io.rancher.container.uuid": "6d3dcf5f-28b8-4e60-9bf1-618b76a9a805", + "io.rancher.container.name": "newcontainer", + "io.rancher.container.ip": "10.42.204.104/16" + }, + "logConfig": null, + "lxcConf": null, + "memory": null, + "memorySwap": null, + "nativeContainer": false, + "networkContainerId": null, + "networkMode": "managed", + "pidMode": null, + "ports": null, + "primaryIpAddress": "10.42.204.104", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "registryCredentialId": null, + "removed": null, + "requestedHostId": null, + "restartPolicy": null, + "securityOpt": null, + "startCount": 1, + "startOnCreate": true, + "stdinOpen": false, + "systemContainer": null, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "tty": false, + "user": null, + "uuid": "6d3dcf5f-28b8-4e60-9bf1-618b76a9a805", + "version": "0", + "volumeDriver": null, + "workingDir": null +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_activate_service.json b/libcloud/test/container/fixtures/rancher/ex_activate_service.json new file mode 100644 index 0000000000..a103ef57b7 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_activate_service.json @@ -0,0 +1,198 @@ +{ + "id": "1s6", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s6", + "account": "http://172.30.0.100:8080/v1/services/1s6/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s6/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s6/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s6/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s6/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s6/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s6/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s6/?action=update", + "restart": "http://172.30.0.100:8080/v1/services/1s6/?action=restart", + "remove": "http://172.30.0.100:8080/v1/services/1s6/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s6/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=removeservicelink", + "upgrade": "http://172.30.0.100:8080/v1/services/1s6/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=addservicelink", + "deactivate": "http://172.30.0.100:8080/v1/services/1s6/?action=deactivate" + }, + "name": "123", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T18:28:04Z", + "createdTS": 1474568884000, + "currentScale": 1, + "description": null, + "environmentId": "1e2", + "externalId": null, + "fqdn": null, + "healthState": "healthy", + "kind": "service", + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "metadata": null, + "publicEndpoints": null, + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": { + "inServiceStrategy": { + "batchSize": 1, + "intervalMillis": 2000, + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousLaunchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousSecondaryLaunchConfigs": [], + "secondaryLaunchConfigs": [], + "startFirst": true + }, + "toServiceStrategy": null + }, + "uuid": "c0ae4d08-e20a-45ef-9fb9-ad9f7cdeeb15", + "vip": null +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_activate_stack.json b/libcloud/test/container/fixtures/rancher/ex_activate_stack.json new file mode 100644 index 0000000000..65148eba5e --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_activate_stack.json @@ -0,0 +1,52 @@ +{ + "id": "1e1", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e1", + "account": "http://172.30.0.100:8080/v1/environments/1e1/account", + "services": "http://172.30.0.100:8080/v1/environments/1e1/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e1/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e1/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e1/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e1/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e1/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e1/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e1/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e1/?action=exportconfig" + }, + "name": "Concrete5", + "state": "active", + "accountId": "1a5", + "created": "2016-09-22T17:58:53Z", + "createdTS": 1474567133000, + "description": null, + "dockerCompose": "CMSMysql:\r\n environment:\r\n MYSQL_ROOT_PASSWORD: ${root_password}\r\n MYSQL_DATABASE: ${db_name}\r\n MYSQL_USER: ${db_username}\r\n MYSQL_PASSWORD: ${db_password}\r\n labels:\r\n io.rancher.container.pull_image: always\r\n tty: true\r\n image: mysql\r\n volumes:\r\n - ${db_data_location}:/var/lib/mysql\r\n stdin_open: true\r\n volume_driver: ${volume_driver}\r\n\r\nCMSConfig:\r\n image: opensaas/concrete5\r\n tty: true\r\n stdin_open: true\r\n links:\r\n - CMSMysql:mysql\r\n volumes:\r\n - ${cms_application_data}:/var/www/html/application\r\n - ${cms_packages_data}:/var/www/html/packages\r\n labels:\r\n io.rancher.container.hostname_override: container_name\r\n io.rancher.container.start_once: true\r\n volume_driver: ${volume_driver}\r\n command: bash -c \"chown -R www-data. application; chown -R www-data. packages; sleep 2m; php -f concrete/bin/concrete5.php c5:install --db-server=mysql --db-username=${db_username} --db-password=${db_password} --db-database=${db_name} --site=${cms_sitename} --admin-email=${cms_admin_email} --admin-password=${cms_admin_password} -n -vvv\"\r\n\r\nConcrete5App:\r\n labels:\r\n io.rancher.container.pull_image: always\r\n io.rancher.sidekicks: CMSConfig\r\n tty: true\r\n links:\r\n - CMSMysql:mysql\r\n image: opensaas/concrete5\r\n volumes:\r\n - ${cms_application_data}:/var/www/html/application\r\n - ${cms_packages_data}:/var/www/html/packages\r\n volume_driver: ${volume_driver}\r\n stdin_open: true", + "environment": { + "root_password": "password", + "db_name": "CMS_DB", + "db_username": "CMS_USER", + "db_password": "password", + "db_data_location": "CMS_DB_DATA", + "volume_driver": "", + "cms_application_data": "CMS_APP_DATA", + "cms_packages_data": "CMS_PACK_DATA", + "cms_admin_email": "admin@example.com", + "cms_admin_password": "password", + "cms_sitename": "MySite" + }, + "externalId": "catalog://community:Concrete5:1", + "healthState": "unhealthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": ".catalog:\r\n name: \"Concrete5\"\r\n version: \"v0.2\"\r\n description: \"Concrete5 CMS\"\r\n uuid: Concrete5-1\r\n minimum_rancher_version: v0.51.0\r\n questions:\r\n - variable: root_password\r\n description: \"MySQL root password - keep this password complex and secure\"\r\n label: \"MySQL Root Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: db_name\r\n description: \"MySQL Database Name - to use in the Concrete5 setup\"\r\n label: \"MySQL Database Name\"\r\n required: true\r\n default: \"CMS_DB\"\r\n type: \"string\"\r\n - variable: db_username\r\n description: \"MySQL Username - to use in the Concrete5 setup\"\r\n label: \"MySQL Username\"\r\n required: true\r\n default: \"CMS_USER\"\r\n type: \"string\"\r\n - variable: db_password\r\n description: \"MySQL password for the above user - to use in the Concrete5 setup\"\r\n label: \"MySQL Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: db_data_location\r\n description: \"Location on the host for the database files\"\r\n label: \"DB Data Location\"\r\n required: true\r\n default: \"CMS_DB_DATA\"\r\n type: \"string\"\r\n - variable: volume_driver\r\n description: \"Volume Driver for the persistant data locations requires docker 1.7\"\r\n label: \"Volume Driver\"\r\n type: \"string\"\r\n - variable: cms_application_data\r\n description: \"Concrcte5 application folder for persistant data storage\"\r\n label: \"Application Folder\"\r\n required: true\r\n default: \"CMS_APP_DATA\"\r\n type: \"string\"\r\n - variable: cms_packages_data\r\n description: \"Concrcte5 packages folder for persistant data storage\"\r\n label: \"Packages Folder\"\r\n required: true\r\n default: \"CMS_PACK_DATA\"\r\n type: \"string\"\r\n - variable: cms_admin_email\r\n description: \"Concrcete5 admin email address\"\r\n label: \"Admin Email\"\r\n required: true\r\n default: \"admin@example.com\"\r\n type: \"string\"\r\n - variable: cms_admin_password\r\n description: \"Concrcete5 admin password\"\r\n label: \"Admin Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: cms_sitename\r\n description: \"Concrcete5 Sitename\"\r\n label: \"Sitename\"\r\n required: true\r\n default: \"MySite\"\r\n type: \"string\"\r\nCMSMysql:\r\n scale: 1\r\nConcrete5App:\r\n scale: 1\r\n\r\n", + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "e129ed27-3823-4e2e-af62-4565d68995d4" +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_deploy_service.json b/libcloud/test/container/fixtures/rancher/ex_deploy_service.json new file mode 100644 index 0000000000..e30bc47800 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_deploy_service.json @@ -0,0 +1,66 @@ +{ + "id": "1s13", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s13", + "account": "http://172.30.0.100:8080/v1/services/1s13/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s13/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s13/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s13/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s13/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s13/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s13/containerstats" + }, + "actions": { + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s13/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s13/?action=removeservicelink", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s13/?action=addservicelink" + }, + "name": "newservice", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-10-06T15:31:35Z", + "createdTS": 1475767895000, + "currentScale": 1, + "description": null, + "environmentId": "1e6", + "externalId": null, + "fqdn": null, + "healthState": "unhealthy", + "kind": "service", + "launchConfig": { + "environment": { + "root_password": "password" + }, + "imageUuid": "docker:rlister/hastebin:latest", + "kind": "container", + "networkMode": "managed", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": false, + "tty": false, + "version": "0", + "vcpu": 1 + }, + "metadata": null, + "publicEndpoints": null, + "removed": "2016-10-06T15:45:03Z", + "removedTS": 1475768703000, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "de2cd54f-9936-49fb-a41a-35653c4510f7", + "vip": null +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_deploy_stack.json b/libcloud/test/container/fixtures/rancher/ex_deploy_stack.json new file mode 100644 index 0000000000..38b1db449e --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_deploy_stack.json @@ -0,0 +1,40 @@ +{ + "id": "1e9", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e9", + "account": "http://172.30.0.100:8080/v1/environments/1e9/account", + "services": "http://172.30.0.100:8080/v1/environments/1e9/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e9/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e9/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e9/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e9/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e9/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e9/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e9/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e9/?action=exportconfig" + }, + "name": "newstack", + "state": "active", + "accountId": "1a5", + "created": "2016-10-06T14:12:34Z", + "createdTS": 1475763154000, + "description": null, + "dockerCompose": null, + "environment": {"root_password": "password"}, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "7f8b1836-5619-4e19-adfe-6967fe55bda7" +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_destroy_service.json b/libcloud/test/container/fixtures/rancher/ex_destroy_service.json new file mode 100644 index 0000000000..6af70adabd --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_destroy_service.json @@ -0,0 +1,66 @@ +{ + "id": "1s13", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s13", + "account": "http://172.30.0.100:8080/v1/services/1s13/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s13/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s13/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s13/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s13/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s13/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s13/containerstats" + }, + "actions": { + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s13/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s13/?action=removeservicelink", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s13/?action=addservicelink" + }, + "name": "newservice", + "state": "removing", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-10-06T15:31:35Z", + "createdTS": 1475767895000, + "currentScale": 1, + "description": null, + "environmentId": "1e6", + "externalId": null, + "fqdn": null, + "healthState": "unhealthy", + "kind": "service", + "launchConfig": { + "environment": { + "root_password": "password" + }, + "imageUuid": "docker:rlister/hastebin:latest", + "kind": "container", + "networkMode": "managed", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": false, + "tty": false, + "version": "0", + "vcpu": 1 + }, + "metadata": null, + "publicEndpoints": null, + "removed": "2016-10-06T15:45:03Z", + "removedTS": 1475768703000, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "de2cd54f-9936-49fb-a41a-35653c4510f7", + "vip": null +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_destroy_stack.json b/libcloud/test/container/fixtures/rancher/ex_destroy_stack.json new file mode 100644 index 0000000000..daef943c63 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_destroy_stack.json @@ -0,0 +1,40 @@ +{ + "id": "1e10", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e10", + "account": "http://172.30.0.100:8080/v1/environments/1e10/account", + "services": "http://172.30.0.100:8080/v1/environments/1e10/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e10/composeconfig" + }, + "actions": { + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e10/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e10/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e10/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e10/?action=exportconfig" + }, + "name": "newstack1", + "state": "removing", + "accountId": "1a5", + "created": "2016-10-06T14:15:41Z", + "createdTS": 1475763341000, + "description": null, + "dockerCompose": null, + "environment": { + "root_password": "password" + }, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": "2016-10-06T14:56:16Z", + "removedTS": 1475765776000, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "289f380f-d00a-4faf-b69f-53a559dbfd05" +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_list_services.json b/libcloud/test/container/fixtures/rancher/ex_list_services.json new file mode 100644 index 0000000000..789bca8641 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_list_services.json @@ -0,0 +1,536 @@ +{ + "type": "collection", + "resourceType": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services" + }, + "createTypes": { + "dnsService": "http://172.30.0.100:8080/v1/dnsservices", + "externalService": "http://172.30.0.100:8080/v1/externalservices", + "loadBalancerService": "http://172.30.0.100:8080/v1/loadbalancerservices", + "service": "http://172.30.0.100:8080/v1/services" + }, + "actions": {}, + "data": [ + { + "id": "1s1", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s1", + "account": "http://172.30.0.100:8080/v1/services/1s1/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s1/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s1/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s1/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s1/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s1/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s1/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s1/?action=update", + "remove": "http://172.30.0.100:8080/v1/services/1s1/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s1/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s1/?action=removeservicelink", + "activate": "http://172.30.0.100:8080/v1/services/1s1/?action=activate", + "upgrade": "http://172.30.0.100:8080/v1/services/1s1/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s1/?action=addservicelink" + }, + "name": "CMSMysql", + "state": "inactive", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T17:58:54Z", + "createdTS": 1474567134000, + "currentScale": 1, + "description": null, + "environmentId": "1e1", + "externalId": null, + "fqdn": null, + "healthState": "unhealthy", + "kind": "service", + "launchConfig": { + "dataVolumes": [ + "CMS_DB_DATA:/var/lib/mysql" + ], + "environment": { + "MYSQL_DATABASE": "CMS_DB", + "MYSQL_PASSWORD": "password", + "MYSQL_ROOT_PASSWORD": "password", + "MYSQL_USER": "CMS_USER" + }, + "imageUuid": "docker:mysql", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always", + "io.rancher.service.hash": "c5d6bacef4be47a5ca5d1517a1d33319d024cdde" + }, + "logConfig": {}, + "networkMode": "managed", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "version": "0", + "vcpu": 1 + }, + "metadata": { + "io.rancher.service.hash": "41ccfd7f8023f2efcc758a925a9f461d607c990d" + }, + "publicEndpoints": null, + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": false, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "85f4e9fc-c311-45a0-9a1a-a9da229aaa2a", + "vip": null + }, + { + "id": "1s2", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s2", + "account": "http://172.30.0.100:8080/v1/services/1s2/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s2/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s2/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s2/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s2/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s2/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s2/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s2/?action=update", + "remove": "http://172.30.0.100:8080/v1/services/1s2/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s2/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s2/?action=removeservicelink", + "activate": "http://172.30.0.100:8080/v1/services/1s2/?action=activate", + "upgrade": "http://172.30.0.100:8080/v1/services/1s2/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s2/?action=addservicelink" + }, + "name": "Concrete5App", + "state": "inactive", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 2, + "created": "2016-09-22T17:58:54Z", + "createdTS": 1474567134000, + "currentScale": 1, + "description": null, + "environmentId": "1e1", + "externalId": null, + "fqdn": null, + "healthState": "degraded", + "kind": "service", + "launchConfig": { + "dataVolumes": [ + "CMS_APP_DATA:/var/www/html/application", + "CMS_PACK_DATA:/var/www/html/packages" + ], + "imageUuid": "docker:opensaas/concrete5", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always", + "io.rancher.service.hash": "6033469e7596fd16896eb87b3a99f50af2dbf522", + "io.rancher.sidekicks": "CMSConfig" + }, + "logConfig": {}, + "networkMode": "managed", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "version": "0", + "vcpu": 1 + }, + "metadata": { + "io.rancher.service.hash": "037726f2f6d389022953a652a5d3e5775415d0b0" + }, + "publicEndpoints": null, + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [ + { + "command": [ + "bash", + "-c", + "chown -R www-data. application; chown -R www-data. packages; sleep 2m; php -f concrete/bin/concrete5.php c5:install --db-server=mysql --db-username=CMS_USER --db-password=password --db-database=CMS_DB --site=MySite --admin-email=admin@example.com --admin-password=password -n -vvv" + ], + "dataVolumes": [ + "CMS_APP_DATA:/var/www/html/application", + "CMS_PACK_DATA:/var/www/html/packages" + ], + "imageUuid": "docker:opensaas/concrete5", + "labels": { + "io.rancher.container.hostname_override": "container_name", + "io.rancher.container.start_once": "true", + "io.rancher.service.hash": "db08c70dbb11ff2955a5cac93c2c6e5e1ac95e7e" + }, + "logConfig": {}, + "name": "CMSConfig", + "networkMode": "managed", + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "kind": "container", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "vcpu": 1, + "version": "0" + } + ], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": false, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "1d824bd6-e18b-4ac4-8ea1-5cd0a3c7e234", + "vip": null + }, + { + "id": "1s3", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s3", + "account": "http://172.30.0.100:8080/v1/services/1s3/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s3/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s3/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s3/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s3/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s3/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s3/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s3/?action=update", + "restart": "http://172.30.0.100:8080/v1/services/1s3/?action=restart", + "remove": "http://172.30.0.100:8080/v1/services/1s3/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s3/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s3/?action=removeservicelink", + "upgrade": "http://172.30.0.100:8080/v1/services/1s3/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s3/?action=addservicelink", + "deactivate": "http://172.30.0.100:8080/v1/services/1s3/?action=deactivate" + }, + "name": "ghost", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T18:00:26Z", + "createdTS": 1474567226000, + "currentScale": 1, + "description": null, + "environmentId": "1e2", + "externalId": null, + "fqdn": null, + "healthState": "healthy", + "kind": "service", + "launchConfig": { + "imageUuid": "docker:ghost", + "kind": "container", + "labels": { + "io.rancher.service.hash": "af9b5ddd2891271b12a88129e2bc37ff57998182" + }, + "logConfig": {}, + "networkMode": "managed", + "ports": [ + "80:2368/tcp" + ], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": false, + "tty": false, + "version": "0", + "vcpu": 1 + }, + "metadata": { + "io.rancher.service.hash": "f49280e1f709117b76693b638834791e4f4ef0fd" + }, + "publicEndpoints": [ + { + "ipAddress": "172.30.0.101", + "port": 80, + "serviceId": "1s3", + "hostId": "1h1", + "instanceId": "1i5" + } + ], + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": false, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "c2ce7050-e5b5-42c7-a9fb-8ed8d33a4884", + "vip": null + }, + { + "id": "1s6", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s6", + "account": "http://172.30.0.100:8080/v1/services/1s6/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s6/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s6/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s6/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s6/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s6/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s6/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s6/?action=update", + "restart": "http://172.30.0.100:8080/v1/services/1s6/?action=restart", + "remove": "http://172.30.0.100:8080/v1/services/1s6/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s6/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=removeservicelink", + "upgrade": "http://172.30.0.100:8080/v1/services/1s6/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=addservicelink", + "deactivate": "http://172.30.0.100:8080/v1/services/1s6/?action=deactivate" + }, + "name": "123", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T18:28:04Z", + "createdTS": 1474568884000, + "currentScale": 1, + "description": null, + "environmentId": "1e2", + "externalId": null, + "fqdn": null, + "healthState": "healthy", + "kind": "service", + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "metadata": null, + "publicEndpoints": null, + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": { + "inServiceStrategy": { + "batchSize": 1, + "intervalMillis": 2000, + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousLaunchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousSecondaryLaunchConfigs": [], + "secondaryLaunchConfigs": [], + "startFirst": true + }, + "toServiceStrategy": null + }, + "uuid": "c0ae4d08-e20a-45ef-9fb9-ad9f7cdeeb15", + "vip": null + } + ], + "sortLinks": { + "accountId": "http://172.30.0.100:8080/v1/services?limit=4&sort=accountId", + "createIndex": "http://172.30.0.100:8080/v1/services?limit=4&sort=createIndex", + "created": "http://172.30.0.100:8080/v1/services?limit=4&sort=created", + "description": "http://172.30.0.100:8080/v1/services?limit=4&sort=description", + "environmentId": "http://172.30.0.100:8080/v1/services?limit=4&sort=environmentId", + "externalId": "http://172.30.0.100:8080/v1/services?limit=4&sort=externalId", + "healthState": "http://172.30.0.100:8080/v1/services?limit=4&sort=healthState", + "id": "http://172.30.0.100:8080/v1/services?limit=4&sort=id", + "kind": "http://172.30.0.100:8080/v1/services?limit=4&sort=kind", + "name": "http://172.30.0.100:8080/v1/services?limit=4&sort=name", + "removeTime": "http://172.30.0.100:8080/v1/services?limit=4&sort=removeTime", + "removed": "http://172.30.0.100:8080/v1/services?limit=4&sort=removed", + "selectorContainer": "http://172.30.0.100:8080/v1/services?limit=4&sort=selectorContainer", + "selectorLink": "http://172.30.0.100:8080/v1/services?limit=4&sort=selectorLink", + "state": "http://172.30.0.100:8080/v1/services?limit=4&sort=state", + "uuid": "http://172.30.0.100:8080/v1/services?limit=4&sort=uuid", + "vip": "http://172.30.0.100:8080/v1/services?limit=4&sort=vip" + }, + "pagination": { + "first": null, + "previous": null, + "next": "http://172.30.0.100:8080/v1/services?limit=4&marker=m4", + "limit": 4, + "total": null, + "partial": true + }, + "sort": null, + "filters": { + "accountId": null, + "createIndex": null, + "created": null, + "description": null, + "environmentId": null, + "externalId": null, + "healthState": null, + "id": null, + "kind": null, + "name": null, + "removeTime": null, + "removed": null, + "selectorContainer": null, + "selectorLink": null, + "state": null, + "uuid": null, + "vip": null + }, + "createDefaults": {} +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_list_stacks.json b/libcloud/test/container/fixtures/rancher/ex_list_stacks.json new file mode 100644 index 0000000000..d2d1c3c42e --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_list_stacks.json @@ -0,0 +1,310 @@ +{ + "type": "collection", + "resourceType": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments" + }, + "createTypes": { + "composeProject": "http://172.30.0.100:8080/v1/composeprojects", + "environment": "http://172.30.0.100:8080/v1/environments" + }, + "actions": {}, + "data": [ + { + "id": "1e1", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e1", + "account": "http://172.30.0.100:8080/v1/environments/1e1/account", + "services": "http://172.30.0.100:8080/v1/environments/1e1/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e1/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e1/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e1/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e1/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e1/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e1/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e1/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e1/?action=exportconfig" + }, + "name": "Concrete5", + "state": "active", + "accountId": "1a5", + "created": "2016-09-22T17:58:53Z", + "createdTS": 1474567133000, + "description": null, + "dockerCompose": "CMSMysql:\r\n environment:\r\n MYSQL_ROOT_PASSWORD: ${root_password}\r\n MYSQL_DATABASE: ${db_name}\r\n MYSQL_USER: ${db_username}\r\n MYSQL_PASSWORD: ${db_password}\r\n labels:\r\n io.rancher.container.pull_image: always\r\n tty: true\r\n image: mysql\r\n volumes:\r\n - ${db_data_location}:/var/lib/mysql\r\n stdin_open: true\r\n volume_driver: ${volume_driver}\r\n\r\nCMSConfig:\r\n image: opensaas/concrete5\r\n tty: true\r\n stdin_open: true\r\n links:\r\n - CMSMysql:mysql\r\n volumes:\r\n - ${cms_application_data}:/var/www/html/application\r\n - ${cms_packages_data}:/var/www/html/packages\r\n labels:\r\n io.rancher.container.hostname_override: container_name\r\n io.rancher.container.start_once: true\r\n volume_driver: ${volume_driver}\r\n command: bash -c \"chown -R www-data. application; chown -R www-data. packages; sleep 2m; php -f concrete/bin/concrete5.php c5:install --db-server=mysql --db-username=${db_username} --db-password=${db_password} --db-database=${db_name} --site=${cms_sitename} --admin-email=${cms_admin_email} --admin-password=${cms_admin_password} -n -vvv\"\r\n\r\nConcrete5App:\r\n labels:\r\n io.rancher.container.pull_image: always\r\n io.rancher.sidekicks: CMSConfig\r\n tty: true\r\n links:\r\n - CMSMysql:mysql\r\n image: opensaas/concrete5\r\n volumes:\r\n - ${cms_application_data}:/var/www/html/application\r\n - ${cms_packages_data}:/var/www/html/packages\r\n volume_driver: ${volume_driver}\r\n stdin_open: true", + "environment": { + "root_password": "password", + "db_name": "CMS_DB", + "db_username": "CMS_USER", + "db_password": "password", + "db_data_location": "CMS_DB_DATA", + "volume_driver": "", + "cms_application_data": "CMS_APP_DATA", + "cms_packages_data": "CMS_PACK_DATA", + "cms_admin_email": "admin@example.com", + "cms_admin_password": "password", + "cms_sitename": "MySite" + }, + "externalId": "catalog://community:Concrete5:1", + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": ".catalog:\r\n name: \"Concrete5\"\r\n version: \"v0.2\"\r\n description: \"Concrete5 CMS\"\r\n uuid: Concrete5-1\r\n minimum_rancher_version: v0.51.0\r\n questions:\r\n - variable: root_password\r\n description: \"MySQL root password - keep this password complex and secure\"\r\n label: \"MySQL Root Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: db_name\r\n description: \"MySQL Database Name - to use in the Concrete5 setup\"\r\n label: \"MySQL Database Name\"\r\n required: true\r\n default: \"CMS_DB\"\r\n type: \"string\"\r\n - variable: db_username\r\n description: \"MySQL Username - to use in the Concrete5 setup\"\r\n label: \"MySQL Username\"\r\n required: true\r\n default: \"CMS_USER\"\r\n type: \"string\"\r\n - variable: db_password\r\n description: \"MySQL password for the above user - to use in the Concrete5 setup\"\r\n label: \"MySQL Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: db_data_location\r\n description: \"Location on the host for the database files\"\r\n label: \"DB Data Location\"\r\n required: true\r\n default: \"CMS_DB_DATA\"\r\n type: \"string\"\r\n - variable: volume_driver\r\n description: \"Volume Driver for the persistant data locations requires docker 1.7\"\r\n label: \"Volume Driver\"\r\n type: \"string\"\r\n - variable: cms_application_data\r\n description: \"Concrcte5 application folder for persistant data storage\"\r\n label: \"Application Folder\"\r\n required: true\r\n default: \"CMS_APP_DATA\"\r\n type: \"string\"\r\n - variable: cms_packages_data\r\n description: \"Concrcte5 packages folder for persistant data storage\"\r\n label: \"Packages Folder\"\r\n required: true\r\n default: \"CMS_PACK_DATA\"\r\n type: \"string\"\r\n - variable: cms_admin_email\r\n description: \"Concrcete5 admin email address\"\r\n label: \"Admin Email\"\r\n required: true\r\n default: \"admin@example.com\"\r\n type: \"string\"\r\n - variable: cms_admin_password\r\n description: \"Concrcete5 admin password\"\r\n label: \"Admin Password\"\r\n required: true\r\n default: \"password\"\r\n type: \"string\"\r\n - variable: cms_sitename\r\n description: \"Concrcete5 Sitename\"\r\n label: \"Sitename\"\r\n required: true\r\n default: \"MySite\"\r\n type: \"string\"\r\nCMSMysql:\r\n scale: 1\r\nConcrete5App:\r\n scale: 1\r\n\r\n", + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "e129ed27-3823-4e2e-af62-4565d68995d4" + }, + { + "id": "1e2", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e2", + "account": "http://172.30.0.100:8080/v1/environments/1e2/account", + "services": "http://172.30.0.100:8080/v1/environments/1e2/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e2/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e2/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e2/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e2/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e2/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e2/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e2/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e2/?action=exportconfig" + }, + "name": "ghost", + "state": "active", + "accountId": "1a5", + "created": "2016-09-22T18:00:25Z", + "createdTS": 1474567225000, + "description": null, + "dockerCompose": "ghost:\n image: ghost\n ports:\n - ${public_port}:2368\n", + "environment": { + "public_port": "80" + }, + "externalId": "catalog://community:ghost:0", + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": ".catalog:\n name: \"Ghost\"\n version: \"v0.1-educaas\"\n description: \"Blog powered by Ghost. Requires no database\"\n uuid: ghost-0\n minimum_rancher_version: v0.51.0\n questions:\n - variable: public_port\n description: \"public port to access the blog\"\n label: \"Public Port\"\n required: true\n default: \"80\"\n type: \"int\"\nghost:\n", + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "4c335202-2ca7-41f1-8702-4984518566ec" + }, + { + "id": "1e5", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e5", + "account": "http://172.30.0.100:8080/v1/environments/1e5/account", + "services": "http://172.30.0.100:8080/v1/environments/1e5/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e5/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e5/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e5/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e5/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e5/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e5/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e5/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e5/?action=exportconfig" + }, + "name": "heyk", + "state": "active", + "accountId": "1a5", + "created": "2016-09-29T20:40:14Z", + "createdTS": 1475181614000, + "description": null, + "dockerCompose": null, + "environment": null, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "d5a39304-9247-4a31-8662-7dba98238105" + }, + { + "id": "1e6", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e6", + "account": "http://172.30.0.100:8080/v1/environments/1e6/account", + "services": "http://172.30.0.100:8080/v1/environments/1e6/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e6/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e6/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e6/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e6/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e6/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e6/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e6/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e6/?action=exportconfig" + }, + "name": "ilikegurls", + "state": "active", + "accountId": "1a5", + "created": "2016-10-06T00:40:23Z", + "createdTS": 1475714423000, + "description": null, + "dockerCompose": null, + "environment": null, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "19101511-6dcb-49f7-a8e1-063bcded1956" + }, + { + "id": "1e7", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e7", + "account": "http://172.30.0.100:8080/v1/environments/1e7/account", + "services": "http://172.30.0.100:8080/v1/environments/1e7/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e7/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e7/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e7/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e7/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e7/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e7/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e7/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e7/?action=exportconfig" + }, + "name": "maybethisyear", + "state": "active", + "accountId": "1a5", + "created": "2016-10-06T00:41:17Z", + "createdTS": 1475714477000, + "description": null, + "dockerCompose": null, + "environment": null, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "250c66f6-cd36-4c12-8767-deb5c35d0a05" + }, + { + "id": "1e8", + "type": "environment", + "links": { + "self": "http://172.30.0.100:8080/v1/environments/1e8", + "account": "http://172.30.0.100:8080/v1/environments/1e8/account", + "services": "http://172.30.0.100:8080/v1/environments/1e8/services", + "composeConfig": "http://172.30.0.100:8080/v1/environments/1e8/composeconfig" + }, + "actions": { + "upgrade": "http://172.30.0.100:8080/v1/environments/1e8/?action=upgrade", + "update": "http://172.30.0.100:8080/v1/environments/1e8/?action=update", + "remove": "http://172.30.0.100:8080/v1/environments/1e8/?action=remove", + "addoutputs": "http://172.30.0.100:8080/v1/environments/1e8/?action=addoutputs", + "activateservices": "http://172.30.0.100:8080/v1/environments/1e8/?action=activateservices", + "deactivateservices": "http://172.30.0.100:8080/v1/environments/1e8/?action=deactivateservices", + "exportconfig": "http://172.30.0.100:8080/v1/environments/1e8/?action=exportconfig" + }, + "name": "oh-another", + "state": "active", + "accountId": "1a5", + "created": "2016-10-06T00:51:34Z", + "createdTS": 1475715094000, + "description": null, + "dockerCompose": null, + "environment": null, + "externalId": null, + "healthState": "healthy", + "kind": "environment", + "outputs": null, + "previousEnvironment": null, + "previousExternalId": null, + "rancherCompose": null, + "removed": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "uuid": "a777dd5e-e524-43c8-8783-d7bb14bcffb6" + } + ], + "sortLinks": { + "accountId": "http://172.30.0.100:8080/v1/environments?limit=6&sort=accountId", + "created": "http://172.30.0.100:8080/v1/environments?limit=6&sort=created", + "description": "http://172.30.0.100:8080/v1/environments?limit=6&sort=description", + "externalId": "http://172.30.0.100:8080/v1/environments?limit=6&sort=externalId", + "healthState": "http://172.30.0.100:8080/v1/environments?limit=6&sort=healthState", + "id": "http://172.30.0.100:8080/v1/environments?limit=6&sort=id", + "kind": "http://172.30.0.100:8080/v1/environments?limit=6&sort=kind", + "name": "http://172.30.0.100:8080/v1/environments?limit=6&sort=name", + "removeTime": "http://172.30.0.100:8080/v1/environments?limit=6&sort=removeTime", + "removed": "http://172.30.0.100:8080/v1/environments?limit=6&sort=removed", + "state": "http://172.30.0.100:8080/v1/environments?limit=6&sort=state", + "uuid": "http://172.30.0.100:8080/v1/environments?limit=6&sort=uuid" + }, + "pagination": { + "first": null, + "previous": null, + "next": "http://172.30.0.100:8080/v1/environments?limit=6&marker=m6", + "limit": 6, + "total": null, + "partial": true + }, + "sort": null, + "filters": { + "accountId": null, + "created": null, + "description": null, + "externalId": null, + "healthState": [ + { + "modifier": "eq", + "value": "healthy" + } + ], "id": null, + "kind": null, + "name": null, + "removeTime": null, + "removed": null, + "state": null, + "uuid": null + }, + "createDefaults": {} +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_search_containers.json b/libcloud/test/container/fixtures/rancher/ex_search_containers.json new file mode 100644 index 0000000000..8cd05659e8 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_search_containers.json @@ -0,0 +1,212 @@ +{ + "type": "collection", + "resourceType": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers" + }, + "createTypes": { + "container": "http://172.30.0.100:8080/v1/containers", + "launchConfig": "http://172.30.0.100:8080/v1/launchconfigs", + "virtualMachine": "http://172.30.0.100:8080/v1/virtualmachines" + }, + "actions": {}, + "data": [ + { + "id": "1i2", + "type": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers/1i2", + "account": "http://172.30.0.100:8080/v1/containers/1i2/account", + "credentials": "http://172.30.0.100:8080/v1/containers/1i2/credentials", + "healthcheckInstanceHostMaps": "http://172.30.0.100:8080/v1/containers/1i2/healthcheckinstancehostmaps", + "hosts": "http://172.30.0.100:8080/v1/containers/1i2/hosts", + "instanceLabels": "http://172.30.0.100:8080/v1/containers/1i2/instancelabels", + "instanceLinks": "http://172.30.0.100:8080/v1/containers/1i2/instancelinks", + "instances": "http://172.30.0.100:8080/v1/containers/1i2/instances", + "mounts": "http://172.30.0.100:8080/v1/containers/1i2/mounts", + "ports": "http://172.30.0.100:8080/v1/containers/1i2/ports", + "serviceEvents": "http://172.30.0.100:8080/v1/containers/1i2/serviceevents", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/containers/1i2/serviceexposemaps", + "services": "http://172.30.0.100:8080/v1/containers/1i2/services", + "targetInstanceLinks": "http://172.30.0.100:8080/v1/containers/1i2/targetinstancelinks", + "volumes": "http://172.30.0.100:8080/v1/containers/1i2/volumes", + "stats": "http://172.30.0.100:8080/v1/containers/1i2/stats", + "containerStats": "http://172.30.0.100:8080/v1/containers/1i2/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/containers/1i2/?action=update", + "stop": "http://172.30.0.100:8080/v1/containers/1i2/?action=stop", + "restart": "http://172.30.0.100:8080/v1/containers/1i2/?action=restart", + "migrate": "http://172.30.0.100:8080/v1/containers/1i2/?action=migrate", + "logs": "http://172.30.0.100:8080/v1/containers/1i2/?action=logs", + "setlabels": "http://172.30.0.100:8080/v1/containers/1i2/?action=setlabels", + "execute": "http://172.30.0.100:8080/v1/containers/1i2/?action=execute", + "proxy": "http://172.30.0.100:8080/v1/containers/1i2/?action=proxy" + }, + "name": "Network Agent", + "state": "running", + "accountId": "1a5", + "blkioDeviceOptions": null, + "build": null, + "capAdd": null, + "capDrop": null, + "command": null, + "cpuSet": null, + "cpuShares": null, + "createIndex": null, + "created": "2016-09-22T17:58:57Z", + "createdTS": 1474567137000, + "dataVolumeMounts": {}, + "dataVolumes": [ + "/var/lib/rancher/etc:/var/lib/rancher/etc:ro" + ], + "dataVolumesFrom": null, + "deploymentUnitUuid": null, + "description": null, + "devices": null, + "dns": null, + "dnsSearch": null, + "domainName": null, + "entryPoint": null, + "environment": null, + "expose": null, + "externalId": "129c67adc9fa084fbc8e1f963db0180896b88af3dca69c7e8fe0493284e4651c", + "extraHosts": null, + "firstRunning": "2016-09-22T17:59:11Z", + "firstRunningTS": 1474567151000, + "healthCheck": null, + "healthState": null, + "hostId": "1h1", + "hostname": null, + "imageUuid": "docker:rancher/agent-instance:v0.8.3", + "kind": "container", + "labels": { + "io.rancher.container.system": "NetworkAgent", + "io.rancher.container.uuid": "b0f88089-d28b-4388-93a7-889b750cd7cb", + "io.rancher.container.name": "Network Agent", + "io.rancher.container.agent_id": "2", + "io.rancher.container.ip": "10.42.247.188/16" + }, + "logConfig": null, + "lxcConf": null, + "memory": null, + "memorySwap": null, + "nativeContainer": false, + "networkContainerId": null, + "networkIds": [], + "networkMode": null, + "pidMode": null, + "ports": null, + "primaryIpAddress": "10.42.247.188", + "privileged": true, + "publishAllPorts": false, + "readOnly": false, + "registryCredentialId": null, + "removed": null, + "requestedHostId": null, + "restartPolicy": null, + "securityOpt": null, + "startCount": 3, + "startOnCreate": true, + "stdinOpen": false, + "systemContainer": "NetworkAgent", + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "tty": false, + "user": null, + "uuid": "b0f88089-d28b-4388-93a7-889b750cd7cb", + "version": "0", + "volumeDriver": null, + "workingDir": null + } + ], + "sortLinks": { + "accountId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=accountId", + "agentId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=agentId", + "allocationState": "http://172.30.0.100:8080/v1/containers?limit=2&sort=allocationState", + "compute": "http://172.30.0.100:8080/v1/containers?limit=2&sort=compute", + "createIndex": "http://172.30.0.100:8080/v1/containers?limit=2&sort=createIndex", + "created": "http://172.30.0.100:8080/v1/containers?limit=2&sort=created", + "deploymentUnitUuid": "http://172.30.0.100:8080/v1/containers?limit=2&sort=deploymentUnitUuid", + "description": "http://172.30.0.100:8080/v1/containers?limit=2&sort=description", + "dnsInternal": "http://172.30.0.100:8080/v1/containers?limit=2&sort=dnsInternal", + "dnsSearchInternal": "http://172.30.0.100:8080/v1/containers?limit=2&sort=dnsSearchInternal", + "domain": "http://172.30.0.100:8080/v1/containers?limit=2&sort=domain", + "externalId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=externalId", + "firstRunning": "http://172.30.0.100:8080/v1/containers?limit=2&sort=firstRunning", + "healthState": "http://172.30.0.100:8080/v1/containers?limit=2&sort=healthState", + "healthUpdated": "http://172.30.0.100:8080/v1/containers?limit=2&sort=healthUpdated", + "hostname": "http://172.30.0.100:8080/v1/containers?limit=2&sort=hostname", + "id": "http://172.30.0.100:8080/v1/containers?limit=2&sort=id", + "imageId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=imageId", + "instanceTriggeredStop": "http://172.30.0.100:8080/v1/containers?limit=2&sort=instanceTriggeredStop", + "kind": "http://172.30.0.100:8080/v1/containers?limit=2&sort=kind", + "memoryMb": "http://172.30.0.100:8080/v1/containers?limit=2&sort=memoryMb", + "name": "http://172.30.0.100:8080/v1/containers?limit=2&sort=name", + "nativeContainer": "http://172.30.0.100:8080/v1/containers?limit=2&sort=nativeContainer", + "networkContainerId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=networkContainerId", + "offeringId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=offeringId", + "registryCredentialId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=registryCredentialId", + "removeTime": "http://172.30.0.100:8080/v1/containers?limit=2&sort=removeTime", + "removed": "http://172.30.0.100:8080/v1/containers?limit=2&sort=removed", + "serviceIndexId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=serviceIndexId", + "startCount": "http://172.30.0.100:8080/v1/containers?limit=2&sort=startCount", + "state": "http://172.30.0.100:8080/v1/containers?limit=2&sort=state", + "systemContainer": "http://172.30.0.100:8080/v1/containers?limit=2&sort=systemContainer", + "token": "http://172.30.0.100:8080/v1/containers?limit=2&sort=token", + "userdata": "http://172.30.0.100:8080/v1/containers?limit=2&sort=userdata", + "uuid": "http://172.30.0.100:8080/v1/containers?limit=2&sort=uuid", + "version": "http://172.30.0.100:8080/v1/containers?limit=2&sort=version", + "zoneId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=zoneId" + }, + "pagination": { + "first": null, + "previous": null, + "next": "http://172.30.0.100:8080/v1/containers?limit=2&marker=m2", + "limit": 2, + "total": null, + "partial": true + }, + "sort": null, + "filters": { + "accountId": null, + "agentId": null, + "allocationState": null, + "compute": null, + "createIndex": null, + "created": null, + "deploymentUnitUuid": null, + "description": null, + "dnsInternal": null, + "dnsSearchInternal": null, + "domain": null, + "externalId": null, + "firstRunning": null, + "healthState": null, + "healthUpdated": null, + "hostname": null, + "id": null, + "imageId": null, + "instanceTriggeredStop": null, + "kind": null, + "memoryMb": null, + "name": null, + "nativeContainer": null, + "networkContainerId": null, + "offeringId": null, + "registryCredentialId": null, + "removeTime": null, + "removed": null, + "serviceIndexId": null, + "startCount": null, + "state": null, + "systemContainer": null, + "token": null, + "userdata": null, + "uuid": null, + "version": null, + "zoneId": null + }, + "createDefaults": {} +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/ex_search_services.json b/libcloud/test/container/fixtures/rancher/ex_search_services.json new file mode 100644 index 0000000000..56be671269 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/ex_search_services.json @@ -0,0 +1,346 @@ +{ + "type": "collection", + "resourceType": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services" + }, + "createTypes": { + "dnsService": "http://172.30.0.100:8080/v1/dnsservices", + "externalService": "http://172.30.0.100:8080/v1/externalservices", + "loadBalancerService": "http://172.30.0.100:8080/v1/loadbalancerservices", + "service": "http://172.30.0.100:8080/v1/services" + }, + "actions": {}, + "data": [ + { + "id": "1s3", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s3", + "account": "http://172.30.0.100:8080/v1/services/1s3/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s3/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s3/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s3/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s3/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s3/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s3/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s3/?action=update", + "restart": "http://172.30.0.100:8080/v1/services/1s3/?action=restart", + "remove": "http://172.30.0.100:8080/v1/services/1s3/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s3/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s3/?action=removeservicelink", + "upgrade": "http://172.30.0.100:8080/v1/services/1s3/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s3/?action=addservicelink", + "deactivate": "http://172.30.0.100:8080/v1/services/1s3/?action=deactivate" + }, + "name": "ghost", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T18:00:26Z", + "createdTS": 1474567226000, + "currentScale": 1, + "description": null, + "environmentId": "1e2", + "externalId": null, + "fqdn": null, + "healthState": "healthy", + "kind": "service", + "launchConfig": { + "imageUuid": "docker:ghost", + "kind": "container", + "labels": { + "io.rancher.service.hash": "af9b5ddd2891271b12a88129e2bc37ff57998182" + }, + "logConfig": {}, + "networkMode": "managed", + "ports": [ + "80:2368/tcp" + ], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "startOnCreate": true, + "stdinOpen": false, + "tty": false, + "version": "0", + "vcpu": 1 + }, + "metadata": { + "io.rancher.service.hash": "f49280e1f709117b76693b638834791e4f4ef0fd" + }, + "publicEndpoints": [ + { + "ipAddress": "172.30.0.101", + "port": 80, + "serviceId": "1s3", + "hostId": "1h1", + "instanceId": "1i5" + } + ], + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": false, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": null, + "uuid": "c2ce7050-e5b5-42c7-a9fb-8ed8d33a4884", + "vip": null + }, + { + "id": "1s6", + "type": "service", + "links": { + "self": "http://172.30.0.100:8080/v1/services/1s6", + "account": "http://172.30.0.100:8080/v1/services/1s6/account", + "consumedbyservices": "http://172.30.0.100:8080/v1/services/1s6/consumedbyservices", + "consumedservices": "http://172.30.0.100:8080/v1/services/1s6/consumedservices", + "environment": "http://172.30.0.100:8080/v1/services/1s6/environment", + "instances": "http://172.30.0.100:8080/v1/services/1s6/instances", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/services/1s6/serviceexposemaps", + "containerStats": "http://172.30.0.100:8080/v1/services/1s6/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/services/1s6/?action=update", + "restart": "http://172.30.0.100:8080/v1/services/1s6/?action=restart", + "remove": "http://172.30.0.100:8080/v1/services/1s6/?action=remove", + "setservicelinks": "http://172.30.0.100:8080/v1/services/1s6/?action=setservicelinks", + "removeservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=removeservicelink", + "upgrade": "http://172.30.0.100:8080/v1/services/1s6/?action=upgrade", + "addservicelink": "http://172.30.0.100:8080/v1/services/1s6/?action=addservicelink", + "deactivate": "http://172.30.0.100:8080/v1/services/1s6/?action=deactivate" + }, + "name": "123", + "state": "active", + "accountId": "1a5", + "assignServiceIpAddress": false, + "createIndex": 1, + "created": "2016-09-22T18:28:04Z", + "createdTS": 1474568884000, + "currentScale": 1, + "description": null, + "environmentId": "1e2", + "externalId": null, + "fqdn": null, + "healthState": "healthy", + "kind": "service", + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "metadata": null, + "publicEndpoints": null, + "removed": null, + "retainIp": null, + "scale": 1, + "scalePolicy": null, + "secondaryLaunchConfigs": [], + "selectorContainer": null, + "selectorLink": null, + "startOnCreate": true, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "upgrade": { + "inServiceStrategy": { + "batchSize": 1, + "intervalMillis": 2000, + "launchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0bdea468-c3e9-4562-951c-d543958e966a", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousLaunchConfig": { + "capAdd": [], + "capDrop": [], + "count": null, + "cpuSet": null, + "cpuShares": null, + "dataVolumes": [], + "dataVolumesFrom": [], + "description": null, + "devices": [], + "dns": [], + "dnsSearch": [], + "domainName": null, + "hostname": null, + "imageUuid": "docker:ubuntu:trusty", + "kind": "container", + "labels": { + "io.rancher.container.pull_image": "always" + }, + "logConfig": { + "config": {}, + "driver": "" + }, + "memory": null, + "memoryMb": null, + "memorySwap": null, + "networkMode": "managed", + "pidMode": null, + "ports": [], + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "requestedIpAddress": null, + "startOnCreate": true, + "stdinOpen": true, + "tty": true, + "user": null, + "userdata": null, + "version": "0", + "volumeDriver": null, + "workingDir": null, + "dataVolumesFromLaunchConfigs": [], + "networkLaunchConfig": null, + "vcpu": 1 + }, + "previousSecondaryLaunchConfigs": [], + "secondaryLaunchConfigs": [], + "startFirst": true + }, + "toServiceStrategy": null + }, + "uuid": "c0ae4d08-e20a-45ef-9fb9-ad9f7cdeeb15", + "vip": null + } + ], + "sortLinks": { + "accountId": "http://172.30.0.100:8080/v1/services?limit=4&sort=accountId", + "createIndex": "http://172.30.0.100:8080/v1/services?limit=4&sort=createIndex", + "created": "http://172.30.0.100:8080/v1/services?limit=4&sort=created", + "description": "http://172.30.0.100:8080/v1/services?limit=4&sort=description", + "environmentId": "http://172.30.0.100:8080/v1/services?limit=4&sort=environmentId", + "externalId": "http://172.30.0.100:8080/v1/services?limit=4&sort=externalId", + "healthState": "http://172.30.0.100:8080/v1/services?limit=4&sort=healthState", + "id": "http://172.30.0.100:8080/v1/services?limit=4&sort=id", + "kind": "http://172.30.0.100:8080/v1/services?limit=4&sort=kind", + "name": "http://172.30.0.100:8080/v1/services?limit=4&sort=name", + "removeTime": "http://172.30.0.100:8080/v1/services?limit=4&sort=removeTime", + "removed": "http://172.30.0.100:8080/v1/services?limit=4&sort=removed", + "selectorContainer": "http://172.30.0.100:8080/v1/services?limit=4&sort=selectorContainer", + "selectorLink": "http://172.30.0.100:8080/v1/services?limit=4&sort=selectorLink", + "state": "http://172.30.0.100:8080/v1/services?limit=4&sort=state", + "uuid": "http://172.30.0.100:8080/v1/services?limit=4&sort=uuid", + "vip": "http://172.30.0.100:8080/v1/services?limit=4&sort=vip" + }, + "pagination": { + "first": null, + "previous": null, + "next": "http://172.30.0.100:8080/v1/services?limit=4&marker=m4", + "limit": 4, + "total": null, + "partial": true + }, + "sort": null, + "filters": { + "accountId": null, + "createIndex": null, + "created": null, + "description": null, + "environmentId": null, + "externalId": null, + "healthState": null, + "id": null, + "kind": null, + "name": null, + "removeTime": null, + "removed": null, + "selectorContainer": null, + "selectorLink": null, + "state": null, + "uuid": null, + "vip": null + }, + "createDefaults": {} +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/list_containers.json b/libcloud/test/container/fixtures/rancher/list_containers.json new file mode 100644 index 0000000000..e55d786379 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/list_containers.json @@ -0,0 +1,336 @@ +{ + "type": "collection", + "resourceType": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers" + }, + "createTypes": { + "container": "http://172.30.0.100:8080/v1/containers", + "launchConfig": "http://172.30.0.100:8080/v1/launchconfigs", + "virtualMachine": "http://172.30.0.100:8080/v1/virtualmachines" + }, + "actions": {}, + "data": [ + { + "id": "1i1", + "type": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers/1i1", + "account": "http://172.30.0.100:8080/v1/containers/1i1/account", + "credentials": "http://172.30.0.100:8080/v1/containers/1i1/credentials", + "healthcheckInstanceHostMaps": "http://172.30.0.100:8080/v1/containers/1i1/healthcheckinstancehostmaps", + "hosts": "http://172.30.0.100:8080/v1/containers/1i1/hosts", + "instanceLabels": "http://172.30.0.100:8080/v1/containers/1i1/instancelabels", + "instanceLinks": "http://172.30.0.100:8080/v1/containers/1i1/instancelinks", + "instances": "http://172.30.0.100:8080/v1/containers/1i1/instances", + "mounts": "http://172.30.0.100:8080/v1/containers/1i1/mounts", + "ports": "http://172.30.0.100:8080/v1/containers/1i1/ports", + "serviceEvents": "http://172.30.0.100:8080/v1/containers/1i1/serviceevents", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/containers/1i1/serviceexposemaps", + "services": "http://172.30.0.100:8080/v1/containers/1i1/services", + "targetInstanceLinks": "http://172.30.0.100:8080/v1/containers/1i1/targetinstancelinks", + "volumes": "http://172.30.0.100:8080/v1/containers/1i1/volumes", + "stats": "http://172.30.0.100:8080/v1/containers/1i1/stats", + "containerStats": "http://172.30.0.100:8080/v1/containers/1i1/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/containers/1i1/?action=update", + "error": "http://172.30.0.100:8080/v1/containers/1i1/?action=error", + "remove": "http://172.30.0.100:8080/v1/containers/1i1/?action=remove", + "start": "http://172.30.0.100:8080/v1/containers/1i1/?action=start", + "logs": "http://172.30.0.100:8080/v1/containers/1i1/?action=logs", + "setlabels": "http://172.30.0.100:8080/v1/containers/1i1/?action=setlabels" + }, + "name": "Concrete5_CMSMysql_1", + "state": "stopped", + "accountId": "1a5", + "blkioDeviceOptions": null, + "build": null, + "capAdd": null, + "capDrop": null, + "command": null, + "cpuSet": null, + "cpuShares": null, + "createIndex": 1, + "created": "2016-09-22T17:58:55Z", + "createdTS": 1474567135000, + "dataVolumeMounts": {}, + "dataVolumes": [ + "CMS_DB_DATA:/var/lib/mysql" + ], + "dataVolumesFrom": null, + "deploymentUnitUuid": "761675e2-7fc7-4fbf-a825-132429a44349", + "description": null, + "devices": null, + "dns": [ + "169.254.169.250" + ], + "dnsSearch": [ + "concrete5.rancher.internal", + "cmsmysql.concrete5.rancher.internal", + "rancher.internal" + ], + "dockerPorts": [], + "domainName": null, + "entryPoint": null, + "environment": { + "MYSQL_DATABASE": "CMS_DB", + "MYSQL_PASSWORD": "password", + "MYSQL_ROOT_PASSWORD": "password", + "MYSQL_USER": "CMS_USER" + }, + "expose": null, + "externalId": "957136960bd1b51acf5a6c0079d0e35b8d5c14f54722a3063ceb868e85fd3758", + "extraHosts": null, + "firstRunning": "2016-09-22T17:59:40Z", + "firstRunningTS": 1474567180000, + "healthCheck": null, + "healthState": null, + "hostId": "1h1", + "hostname": null, + "imageUuid": "docker:mysql", + "kind": "container", + "labels": { + "io.rancher.project.name": "Concrete5", + "io.rancher.container.pull_image": "always", + "io.rancher.service.deployment.unit": "761675e2-7fc7-4fbf-a825-132429a44349", + "io.rancher.service.launch.config": "io.rancher.service.primary.launch.config", + "io.rancher.project_service.name": "Concrete5/CMSMysql", + "io.rancher.stack.name": "Concrete5", + "io.rancher.stack_service.name": "Concrete5/CMSMysql", + "io.rancher.service.hash": "c5d6bacef4be47a5ca5d1517a1d33319d024cdde", + "io.rancher.container.uuid": "a1140e7c-9260-423e-a7d0-8f5f7bb8e946", + "io.rancher.container.name": "Concrete5_CMSMysql_1", + "io.rancher.container.ip": "10.42.80.96/16" + }, + "logConfig": {}, + "lxcConf": null, + "memory": null, + "memorySwap": null, + "nativeContainer": false, + "networkContainerId": null, + "networkMode": "managed", + "pidMode": null, + "ports": null, + "primaryIpAddress": "10.42.80.96", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "registryCredentialId": null, + "removed": null, + "requestedHostId": null, + "restartPolicy": null, + "securityOpt": null, + "startCount": 4, + "startOnCreate": true, + "stdinOpen": true, + "systemContainer": null, + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "tty": true, + "user": null, + "uuid": "a1140e7c-9260-423e-a7d0-8f5f7bb8e946", + "version": "0", + "volumeDriver": null, + "workingDir": null + }, + { + "id": "1i2", + "type": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers/1i2", + "account": "http://172.30.0.100:8080/v1/containers/1i2/account", + "credentials": "http://172.30.0.100:8080/v1/containers/1i2/credentials", + "healthcheckInstanceHostMaps": "http://172.30.0.100:8080/v1/containers/1i2/healthcheckinstancehostmaps", + "hosts": "http://172.30.0.100:8080/v1/containers/1i2/hosts", + "instanceLabels": "http://172.30.0.100:8080/v1/containers/1i2/instancelabels", + "instanceLinks": "http://172.30.0.100:8080/v1/containers/1i2/instancelinks", + "instances": "http://172.30.0.100:8080/v1/containers/1i2/instances", + "mounts": "http://172.30.0.100:8080/v1/containers/1i2/mounts", + "ports": "http://172.30.0.100:8080/v1/containers/1i2/ports", + "serviceEvents": "http://172.30.0.100:8080/v1/containers/1i2/serviceevents", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/containers/1i2/serviceexposemaps", + "services": "http://172.30.0.100:8080/v1/containers/1i2/services", + "targetInstanceLinks": "http://172.30.0.100:8080/v1/containers/1i2/targetinstancelinks", + "volumes": "http://172.30.0.100:8080/v1/containers/1i2/volumes", + "stats": "http://172.30.0.100:8080/v1/containers/1i2/stats", + "containerStats": "http://172.30.0.100:8080/v1/containers/1i2/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/containers/1i2/?action=update", + "stop": "http://172.30.0.100:8080/v1/containers/1i2/?action=stop", + "restart": "http://172.30.0.100:8080/v1/containers/1i2/?action=restart", + "migrate": "http://172.30.0.100:8080/v1/containers/1i2/?action=migrate", + "logs": "http://172.30.0.100:8080/v1/containers/1i2/?action=logs", + "setlabels": "http://172.30.0.100:8080/v1/containers/1i2/?action=setlabels", + "execute": "http://172.30.0.100:8080/v1/containers/1i2/?action=execute", + "proxy": "http://172.30.0.100:8080/v1/containers/1i2/?action=proxy" + }, + "name": "Network Agent", + "state": "running", + "accountId": "1a5", + "blkioDeviceOptions": null, + "build": null, + "capAdd": null, + "capDrop": null, + "command": null, + "cpuSet": null, + "cpuShares": null, + "createIndex": null, + "created": "2016-09-22T17:58:57Z", + "createdTS": 1474567137000, + "dataVolumeMounts": {}, + "dataVolumes": [ + "/var/lib/rancher/etc:/var/lib/rancher/etc:ro" + ], + "dataVolumesFrom": null, + "deploymentUnitUuid": null, + "description": null, + "devices": null, + "dns": null, + "dnsSearch": null, + "domainName": null, + "entryPoint": null, + "environment": null, + "expose": null, + "externalId": "129c67adc9fa084fbc8e1f963db0180896b88af3dca69c7e8fe0493284e4651c", + "extraHosts": null, + "firstRunning": "2016-09-22T17:59:11Z", + "firstRunningTS": 1474567151000, + "healthCheck": null, + "healthState": null, + "hostId": "1h1", + "hostname": null, + "imageUuid": "docker:rancher/agent-instance:v0.8.3", + "kind": "container", + "labels": { + "io.rancher.container.system": "NetworkAgent", + "io.rancher.container.uuid": "b0f88089-d28b-4388-93a7-889b750cd7cb", + "io.rancher.container.name": "Network Agent", + "io.rancher.container.agent_id": "2", + "io.rancher.container.ip": "10.42.247.188/16" + }, + "logConfig": null, + "lxcConf": null, + "memory": null, + "memorySwap": null, + "nativeContainer": false, + "networkContainerId": null, + "networkIds": [], + "networkMode": null, + "pidMode": null, + "ports": null, + "primaryIpAddress": "10.42.247.188", + "privileged": true, + "publishAllPorts": false, + "readOnly": false, + "registryCredentialId": null, + "removed": null, + "requestedHostId": null, + "restartPolicy": null, + "securityOpt": null, + "startCount": 3, + "startOnCreate": true, + "stdinOpen": false, + "systemContainer": "NetworkAgent", + "transitioning": "no", + "transitioningMessage": null, + "transitioningProgress": null, + "tty": false, + "user": null, + "uuid": "b0f88089-d28b-4388-93a7-889b750cd7cb", + "version": "0", + "volumeDriver": null, + "workingDir": null + } + ], + "sortLinks": { + "accountId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=accountId", + "agentId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=agentId", + "allocationState": "http://172.30.0.100:8080/v1/containers?limit=2&sort=allocationState", + "compute": "http://172.30.0.100:8080/v1/containers?limit=2&sort=compute", + "createIndex": "http://172.30.0.100:8080/v1/containers?limit=2&sort=createIndex", + "created": "http://172.30.0.100:8080/v1/containers?limit=2&sort=created", + "deploymentUnitUuid": "http://172.30.0.100:8080/v1/containers?limit=2&sort=deploymentUnitUuid", + "description": "http://172.30.0.100:8080/v1/containers?limit=2&sort=description", + "dnsInternal": "http://172.30.0.100:8080/v1/containers?limit=2&sort=dnsInternal", + "dnsSearchInternal": "http://172.30.0.100:8080/v1/containers?limit=2&sort=dnsSearchInternal", + "domain": "http://172.30.0.100:8080/v1/containers?limit=2&sort=domain", + "externalId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=externalId", + "firstRunning": "http://172.30.0.100:8080/v1/containers?limit=2&sort=firstRunning", + "healthState": "http://172.30.0.100:8080/v1/containers?limit=2&sort=healthState", + "healthUpdated": "http://172.30.0.100:8080/v1/containers?limit=2&sort=healthUpdated", + "hostname": "http://172.30.0.100:8080/v1/containers?limit=2&sort=hostname", + "id": "http://172.30.0.100:8080/v1/containers?limit=2&sort=id", + "imageId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=imageId", + "instanceTriggeredStop": "http://172.30.0.100:8080/v1/containers?limit=2&sort=instanceTriggeredStop", + "kind": "http://172.30.0.100:8080/v1/containers?limit=2&sort=kind", + "memoryMb": "http://172.30.0.100:8080/v1/containers?limit=2&sort=memoryMb", + "name": "http://172.30.0.100:8080/v1/containers?limit=2&sort=name", + "nativeContainer": "http://172.30.0.100:8080/v1/containers?limit=2&sort=nativeContainer", + "networkContainerId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=networkContainerId", + "offeringId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=offeringId", + "registryCredentialId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=registryCredentialId", + "removeTime": "http://172.30.0.100:8080/v1/containers?limit=2&sort=removeTime", + "removed": "http://172.30.0.100:8080/v1/containers?limit=2&sort=removed", + "serviceIndexId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=serviceIndexId", + "startCount": "http://172.30.0.100:8080/v1/containers?limit=2&sort=startCount", + "state": "http://172.30.0.100:8080/v1/containers?limit=2&sort=state", + "systemContainer": "http://172.30.0.100:8080/v1/containers?limit=2&sort=systemContainer", + "token": "http://172.30.0.100:8080/v1/containers?limit=2&sort=token", + "userdata": "http://172.30.0.100:8080/v1/containers?limit=2&sort=userdata", + "uuid": "http://172.30.0.100:8080/v1/containers?limit=2&sort=uuid", + "version": "http://172.30.0.100:8080/v1/containers?limit=2&sort=version", + "zoneId": "http://172.30.0.100:8080/v1/containers?limit=2&sort=zoneId" + }, + "pagination": { + "first": null, + "previous": null, + "next": "http://172.30.0.100:8080/v1/containers?limit=2&marker=m2", + "limit": 2, + "total": null, + "partial": true + }, + "sort": null, + "filters": { + "accountId": null, + "agentId": null, + "allocationState": null, + "compute": null, + "createIndex": null, + "created": null, + "deploymentUnitUuid": null, + "description": null, + "dnsInternal": null, + "dnsSearchInternal": null, + "domain": null, + "externalId": null, + "firstRunning": null, + "healthState": null, + "healthUpdated": null, + "hostname": null, + "id": null, + "imageId": null, + "instanceTriggeredStop": null, + "kind": null, + "memoryMb": null, + "name": null, + "nativeContainer": null, + "networkContainerId": null, + "offeringId": null, + "registryCredentialId": null, + "removeTime": null, + "removed": null, + "serviceIndexId": null, + "startCount": null, + "state": null, + "systemContainer": null, + "token": null, + "userdata": null, + "uuid": null, + "version": null, + "zoneId": null + }, + "createDefaults": {} +} \ No newline at end of file diff --git a/libcloud/test/container/fixtures/rancher/stop_container.json b/libcloud/test/container/fixtures/rancher/stop_container.json new file mode 100644 index 0000000000..fad41a69e5 --- /dev/null +++ b/libcloud/test/container/fixtures/rancher/stop_container.json @@ -0,0 +1,109 @@ +{ + "id": "1i31", + "type": "container", + "links": { + "self": "http://172.30.0.100:8080/v1/containers/1i31", + "account": "http://172.30.0.100:8080/v1/containers/1i31/account", + "credentials": "http://172.30.0.100:8080/v1/containers/1i31/credentials", + "healthcheckInstanceHostMaps": "http://172.30.0.100:8080/v1/containers/1i31/healthcheckinstancehostmaps", + "hosts": "http://172.30.0.100:8080/v1/containers/1i31/hosts", + "instanceLabels": "http://172.30.0.100:8080/v1/containers/1i31/instancelabels", + "instanceLinks": "http://172.30.0.100:8080/v1/containers/1i31/instancelinks", + "instances": "http://172.30.0.100:8080/v1/containers/1i31/instances", + "mounts": "http://172.30.0.100:8080/v1/containers/1i31/mounts", + "ports": "http://172.30.0.100:8080/v1/containers/1i31/ports", + "serviceEvents": "http://172.30.0.100:8080/v1/containers/1i31/serviceevents", + "serviceExposeMaps": "http://172.30.0.100:8080/v1/containers/1i31/serviceexposemaps", + "services": "http://172.30.0.100:8080/v1/containers/1i31/services", + "targetInstanceLinks": "http://172.30.0.100:8080/v1/containers/1i31/targetinstancelinks", + "volumes": "http://172.30.0.100:8080/v1/containers/1i31/volumes", + "stats": "http://172.30.0.100:8080/v1/containers/1i31/stats", + "containerStats": "http://172.30.0.100:8080/v1/containers/1i31/containerstats" + }, + "actions": { + "update": "http://172.30.0.100:8080/v1/containers/1i31/?action=update", + "error": "http://172.30.0.100:8080/v1/containers/1i31/?action=error", + "remove": "http://172.30.0.100:8080/v1/containers/1i31/?action=remove", + "start": "http://172.30.0.100:8080/v1/containers/1i31/?action=start", + "logs": "http://172.30.0.100:8080/v1/containers/1i31/?action=logs", + "setlabels": "http://172.30.0.100:8080/v1/containers/1i31/?action=setlabels" + }, + "name": "newcontainer", + "state": "stopping", + "accountId": "1a5", + "blkioDeviceOptions": null, + "build": null, + "capAdd": null, + "capDrop": null, + "command": null, + "cpuSet": null, + "cpuShares": null, + "createIndex": null, + "created": "2016-10-06T15:55:58Z", + "createdTS": 1475769358000, + "dataVolumeMounts": {}, + "dataVolumes": [], + "dataVolumesFrom": null, + "deploymentUnitUuid": null, + "description": null, + "devices": null, + "dns": [ + "169.254.169.250" + ], + "dnsSearch": [ + "rancher.internal" + ], + "dockerPorts": [], + "domainName": null, + "entryPoint": null, + "environment": { + "STORAGE_TYPE": "file" + }, + "expose": null, + "externalId": "ab334bd25d25db7b94fdcead8f5c023b05bed424f56243187aa90f5ef7f07b09", + "extraHosts": null, + "firstRunning": "2016-10-06T15:56:00Z", + "firstRunningTS": 1475769360000, + "healthCheck": null, + "healthState": null, + "hostId": "1h1", + "hostname": null, + "imageUuid": "docker:rlister/hastebin:latest", + "kind": "container", + "labels": { + "io.rancher.container.uuid": "6d3dcf5f-28b8-4e60-9bf1-618b76a9a805", + "io.rancher.container.name": "newcontainer", + "io.rancher.container.ip": "10.42.204.104/16" + }, + "logConfig": null, + "lxcConf": null, + "memory": null, + "memorySwap": null, + "nativeContainer": false, + "networkContainerId": null, + "networkMode": "managed", + "pidMode": null, + "ports": null, + "primaryIpAddress": "10.42.204.104", + "privileged": false, + "publishAllPorts": false, + "readOnly": false, + "registryCredentialId": null, + "removed": null, + "requestedHostId": null, + "restartPolicy": null, + "securityOpt": null, + "startCount": 1, + "startOnCreate": true, + "stdinOpen": false, + "systemContainer": null, + "transitioning": "yes", + "transitioningMessage": null, + "transitioningProgress": null, + "tty": false, + "user": null, + "uuid": "6d3dcf5f-28b8-4e60-9bf1-618b76a9a805", + "version": "0", + "volumeDriver": null, + "workingDir": null +} \ No newline at end of file diff --git a/libcloud/test/container/test_rancher.py b/libcloud/test/container/test_rancher.py new file mode 100644 index 0000000000..f9ddc83f7b --- /dev/null +++ b/libcloud/test/container/test_rancher.py @@ -0,0 +1,243 @@ +# 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 sys + +from libcloud.test import unittest + +from libcloud.container.base import ContainerImage +from libcloud.container.drivers.rancher import RancherContainerDriver + +from libcloud.utils.py3 import httplib +from libcloud.test.secrets import CONTAINER_PARAMS_RANCHER +from libcloud.test.file_fixtures import ContainerFileFixtures +from libcloud.test import MockHttp + + +class RancherContainerDriverTestCase(unittest.TestCase): + + def setUp(self): + RancherContainerDriver.connectionCls.conn_classes = ( + RancherMockHttp, RancherMockHttp) + RancherMockHttp.type = None + RancherMockHttp.use_param = 'a' + self.driver = RancherContainerDriver(*CONTAINER_PARAMS_RANCHER) + + # Stacks + def test_ex_list_stacks(self): + stacks = self.driver.ex_list_stacks() + self.assertEqual(len(stacks), 6) + self.assertEqual(stacks[0]['id'], "1e1") + + def test_ex_deploy_stack(self): + stack = self.driver.ex_deploy_stack(name="newstack", + environment={ + "root_password": "password" + }) + self.assertEqual(stack['id'], "1e9") + self.assertEqual(stack['environment']['root_password'], "password") + + def test_ex_get_stack(self): + # also uses ex_deploy_stack.json + stack = self.driver.ex_get_stack("1e9") + self.assertEqual(stack['id'], "1e9") + self.assertEqual(stack['environment']['root_password'], "password") + + def test_ex_search_stacks(self): + stacks = self.driver.ex_search_stacks({"healthState": "healthy"}) + self.assertEqual(len(stacks), 6) + self.assertEqual(stacks[0]['healthState'], "healthy") + + def test_ex_destroy_stack(self): + response = self.driver.ex_destroy_stack("1e10") + self.assertEqual(response, True) + + def test_ex_activate_stack(self): + response = self.driver.ex_activate_stack("1e1") + self.assertEqual(response, True) + + def test_ex_deactivate_stack(self): + # also uses ex_activate_stack.json + response = self.driver.ex_activate_stack("1e1") + self.assertEqual(response, True) + + def test_ex_list_services(self): + services = self.driver.ex_list_services() + self.assertEqual(len(services), 4) + self.assertEqual(services[0]['id'], "1s1") + + def test_ex_deploy_service(self): + image = ContainerImage( + id="hastebin", + name="hastebin", + path="rlister/hastebin", + version="latest", + driver=None + ) + service = self.driver.ex_deploy_service(name="newservice", + environment_id="1e1", + image=image, + environment={ + "root_password": "password" + }) + self.assertEqual(service['id'], "1s13") + self.assertEqual(service['environmentId'], "1e6") + self.assertEqual(service['launchConfig']['environment'] + ['root_password'], "password") + self.assertEqual(service['launchConfig']['imageUuid'], + "docker:rlister/hastebin:latest") + + def test_ex_get_service(self): + # also uses ex_deploy_service.json + service = self.driver.ex_get_service("1s13") + self.assertEqual(service['id'], "1s13") + self.assertEqual(service['environmentId'], "1e6") + self.assertEqual(service['launchConfig']['environment'] + ['root_password'], "password") + + def test_ex_search_services(self): + services = self.driver.ex_search_services({"healthState": "healthy"}) + self.assertEqual(len(services), 2) + self.assertEqual(services[0]['healthState'], "healthy") + + def test_ex_destroy_service(self): + # Not sure how to do these with returns in mockhttp + response = self.driver.ex_destroy_service("1s13") + self.assertEqual(response, True) + + def test_ex_activate_service(self): + response = self.driver.ex_activate_service("1s6") + self.assertEqual(response, True) + + def test_ex_deactivate_service(self): + # also uses ex_activate_service.json + response = self.driver.ex_activate_service("1s6") + self.assertEqual(response, True) + + def test_list_containers(self): + containers = self.driver.list_containers() + self.assertEqual(len(containers), 2) + self.assertEqual(containers[0].id, "1i1") + + def test_deploy_container(self): + container = self.driver.deploy_container( + name='newcontainer', + image=ContainerImage( + id="hastebin", + name="hastebin", + path="rlister/hastebin", + version="latest", + driver=None + ), + environment={"STORAGE_TYPE": "file"}, + networkMode="managed" + ) + self.assertEqual(container.id, '1i31') + self.assertEqual(container.name, 'newcontainer') + self.assertEqual(container.extra['environment'], + {'STORAGE_TYPE': 'file'}) + + def test_get_container(self): + # also uses ex_deploy_container.json + container = self.driver.get_container("1i31") + self.assertEqual(container.id, '1i31') + self.assertEqual(container.name, 'newcontainer') + self.assertEqual(container.extra['environment'], + {'STORAGE_TYPE': 'file'}) + + def test_stop_container(self): + container = self.driver.get_container("1i31") + container.stop() + + def test_ex_search_containers(self): + containers = self.driver.ex_search_containers({"state": "running"}) + self.assertEqual(len(containers), 1) + + def test_destroy_container(self): + container = self.driver.get_container("1i31") + container.destroy() + + +class RancherMockHttp(MockHttp): + fixtures = ContainerFileFixtures('rancher') + + def _v1_environments(self, method, url, body, headers): + if method == 'GET': + return (httplib.OK, self.fixtures.load('ex_list_stacks.json'), {}, + httplib.responses[httplib.OK]) + else: + return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_environments_1e9(self, method, url, body, headers): + return (httplib.OK, self.fixtures.load('ex_deploy_stack.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_environments_1e10(self, method, url, body, headers): + return (httplib.OK, self.fixtures.load('ex_destroy_stack.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_environments_1e1(self, method, url, body, headers): + return (httplib.OK, self.fixtures.load('ex_activate_stack.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_services(self, method, url, body, headers): + if '?healthState=healthy' in url: + return (httplib.OK, self.fixtures.load('ex_search_services.json'), + {}, httplib.responses[httplib.OK]) + elif method == 'GET': + return (httplib.OK, self.fixtures.load('ex_list_services.json'), + {}, httplib.responses[httplib.OK]) + else: + return (httplib.OK, self.fixtures.load('ex_deploy_service.json'), + {}, httplib.responses[httplib.OK]) + + def _v1_services_1s13(self, method, url, body, headers): + if method == 'GET': + return (httplib.OK, self.fixtures.load('ex_deploy_service.json'), + {}, httplib.responses[httplib.OK]) + elif method == 'DELETE': + return (httplib.OK, self.fixtures.load('ex_destroy_service.json'), + {}, httplib.responses[httplib.OK]) + + def _v1_services_1s6(self, method, url, body, headers): + return (httplib.OK, self.fixtures.load('ex_activate_service.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_containers(self, method, url, body, headers): + if '?state=running' in url: + return (httplib.OK, + self.fixtures.load('ex_search_containers.json'), {}, + httplib.responses[httplib.OK]) + elif method == 'POST': + return (httplib.OK, self.fixtures.load('deploy_container.json'), + {}, httplib.responses[httplib.OK]) + return (httplib.OK, self.fixtures.load('list_containers.json'), {}, + httplib.responses[httplib.OK]) + + def _v1_containers_1i31(self, method, url, body, headers): + if method == 'GET': + return (httplib.OK, self.fixtures.load('deploy_container.json'), + {}, httplib.responses[httplib.OK]) + elif method == 'DELETE' or '?action=stop' in url: + return (httplib.OK, self.fixtures.load('stop_container.json'), {}, + httplib.responses[httplib.OK]) + else: + return (httplib.OK, self.fixtures.load('deploy_container.json'), + {}, httplib.responses[httplib.OK]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) diff --git a/libcloud/test/secrets.py-dist b/libcloud/test/secrets.py-dist index f887947bcc..143edc3b44 100644 --- a/libcloud/test/secrets.py-dist +++ b/libcloud/test/secrets.py-dist @@ -93,3 +93,4 @@ DNS_PARAMS_DNSPOD = ('key', ) CONTAINER_PARAMS_DOCKER = ('user', 'password') CONTAINER_PARAMS_ECS = ('user', 'password', 'region') CONTAINER_PARAMS_KUBERNETES = ('user', 'password') +CONTAINER_PARAMS_RANCHER = ('user', 'password') \ No newline at end of file