http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/base.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/base.py b/apache-libcloud-1.0.0rc2/libcloud/container/base.py deleted file mode 100644 index 0980041..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/base.py +++ /dev/null @@ -1,416 +0,0 @@ -# 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. - -from __future__ import with_statement - -from libcloud.common.base import ConnectionUserAndKey, BaseDriver - - -__all__ = [ - 'Container', - 'ContainerImage', - 'ContainerCluster', - 'ClusterLocation', - 'ContainerDriver' -] - - -class Container(object): - """ - Container. - """ - - def __init__(self, id, name, image, state, - ip_addresses, driver, extra=None): - """ - :param id: Container id. - :type id: ``str`` - - :param name: The name of the container. - :type name: ``str`` - - :param image: The image this container was deployed using. - :type image: :class:`.ContainerImage` - - :param state: The state of the container, e.g. running - :type state: :class:`libcloud.container.types.ContainerState` - - :param ip_addresses: A list of IP addresses for this container - :type ip_addresses: ``list`` of ``str`` - - :param driver: ContainerDriver instance. - :type driver: :class:`.ContainerDriver` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - """ - self.id = str(id) if id else None - self.name = name - self.image = image - self.state = state - self.ip_addresses = ip_addresses - self.driver = driver - self.extra = extra or {} - - def start(self): - return self.driver.start_container(container=self) - - def stop(self): - return self.driver.stop_container(container=self) - - def restart(self): - return self.driver.restart_container(container=self) - - def destroy(self): - return self.driver.destroy_container(container=self) - - def __repr__(self): - return ('<Container: id=%s, name=%s,' - 'state=%s, provider=%s ...>' % - (self.id, self.name, self.state, - self.driver.name)) - - -class ContainerImage(object): - """ - Container Image. - """ - - def __init__(self, id, name, path, version, driver, extra=None): - """ - :param id: Container Image id. - :type id: ``str`` - - :param name: The name of the image. - :type name: ``str`` - - :param path: The path to the image - :type path: ``str`` - - :param version: The version of the image - :type version: ``str`` - - :param driver: ContainerDriver instance. - :type driver: :class:`.ContainerDriver` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - """ - self.id = str(id) if id else None - self.name = name - self.path = path - self.version = version - self.driver = driver - self.extra = extra or {} - - def deploy(self, name, parameters, *args, **kwargs): - return self.driver.deploy_container(name=name, - image=self, - parameters=parameters, - *args, - **kwargs) - - def __repr__(self): - return ('<ContainerImage: id=%s, name=%s, path=%s ...>' % - (self.id, self.name, self.path)) - - -class ContainerCluster(object): - """ - A cluster group for containers - """ - - def __init__(self, id, name, driver, extra=None): - """ - :param id: Container Image id. - :type id: ``str`` - - :param name: The name of the image. - :type name: ``str`` - - :param driver: ContainerDriver instance. - :type driver: :class:`.ContainerDriver` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - """ - self.id = str(id) if id else None - self.name = name - self.driver = driver - self.extra = extra or {} - - def list_containers(self): - return self.driver.list_containers(cluster=self) - - def destroy(self): - return self.driver.destroy_cluster(cluster=self) - - def __repr__(self): - return ('<ContainerCluster: id=%s, name=%s, provider=%s ...>' % - (self.id, self.name, self.driver.name)) - - -class ClusterLocation(object): - """ - A physical location where clusters can be. - - >>> from libcloud.container.drivers.dummy import DummyContainerDriver - >>> driver = DummyContainerDriver(0) - >>> location = driver.list_locations()[0] - >>> location.country - 'US' - """ - - def __init__(self, id, name, country, driver): - """ - :param id: Location ID. - :type id: ``str`` - - :param name: Location name. - :type name: ``str`` - - :param country: Location country. - :type country: ``str`` - - :param driver: Driver this location belongs to. - :type driver: :class:`.ContainerDriver` - """ - self.id = str(id) - self.name = name - self.country = country - self.driver = driver - - def __repr__(self): - return (('<ClusterLocation: id=%s, name=%s, country=%s, driver=%s>') - % (self.id, self.name, self.country, self.driver.name)) - - -class ContainerDriver(BaseDriver): - """ - A base ContainerDriver class to derive from - - This class is always subclassed by a specific driver. - """ - connectionCls = ConnectionUserAndKey - name = None - website = None - supports_clusters = False - """ - Whether the driver supports containers being deployed into clusters - """ - - def __init__(self, key, secret=None, secure=True, host=None, port=None, - **kwargs): - """ - :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. Note: Some providers - only support HTTPS, and it is on by default. - :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`` - """ - super(ContainerDriver, self).__init__( - key=key, secret=secret, secure=secure, - host=host, port=port, **kwargs) - - def install_image(self, path): - """ - Install a container image from a remote path. - - :param path: Path to the container image - :type path: ``str`` - - :rtype: :class:`.ContainerImage` - """ - raise NotImplementedError( - 'install_image not implemented for this driver') - - def list_images(self): - """ - List the installed container images - - :rtype: ``list`` of :class:`.ContainerImage` - """ - raise NotImplementedError( - 'list_images not implemented for this driver') - - def list_containers(self, image=None, cluster=None): - """ - List the deployed container images - - :param image: Filter to containers with a certain image - :type image: :class:`.ContainerImage` - - :param cluster: Filter to containers in a cluster - :type cluster: :class:`.ContainerCluster` - - :rtype: ``list`` of :class:`.Container` - """ - raise NotImplementedError( - 'list_containers not implemented for this driver') - - def deploy_container(self, name, image, cluster=None, - parameters=None, start=True): - """ - Deploy an installed container image - - :param name: The name of the new container - :type name: ``str`` - - :param image: The container image to deploy - :type image: :class:`.ContainerImage` - - :param cluster: The cluster to deploy to, None is default - :type cluster: :class:`.ContainerCluster` - - :param parameters: Container Image parameters - :type parameters: ``str`` - - :param start: Start the container on deployment - :type start: ``bool`` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'deploy_container not implemented for this driver') - - def get_container(self, id): - """ - Get a container by ID - - :param id: The ID of the container to get - :type id: ``str`` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'get_container not implemented for this driver') - - def start_container(self, container): - """ - Start a deployed container - - :param container: The container to start - :type container: :class:`.Container` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'start_container not implemented for this driver') - - def stop_container(self, container): - """ - Stop a deployed container - - :param container: The container to stop - :type container: :class:`.Container` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'stop_container not implemented for this driver') - - def restart_container(self, container): - """ - Restart a deployed container - - :param container: The container to restart - :type container: :class:`.Container` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'restart_container not implemented for this driver') - - def destroy_container(self, container): - """ - Destroy a deployed container - - :param container: The container to destroy - :type container: :class:`.Container` - - :rtype: :class:`.Container` - """ - raise NotImplementedError( - 'destroy_container not implemented for this driver') - - def list_locations(self): - """ - Get a list of potential locations to deploy clusters into - - :rtype: ``list`` of :class:`.ClusterLocation` - """ - raise NotImplementedError( - 'list_locations not implemented for this driver') - - def create_cluster(self, name, location=None): - """ - Create a container cluster - - :param name: The name of the cluster - :type name: ``str`` - - :param location: The location to create the cluster in - :type location: :class:`.ClusterLocation` - - :rtype: :class:`.ContainerCluster` - """ - raise NotImplementedError( - 'create_cluster not implemented for this driver') - - def destroy_cluster(self, cluster): - """ - Delete a cluster - - :return: ``True`` if the destroy was successful, otherwise ``False``. - :rtype: ``bool`` - """ - raise NotImplementedError( - 'destroy_cluster not implemented for this driver') - - def list_clusters(self, location=None): - """ - Get a list of potential locations to deploy clusters into - - :param location: The location to search in - :type location: :class:`.ClusterLocation` - - :rtype: ``list`` of :class:`.ContainerCluster` - """ - raise NotImplementedError( - 'list_clusters not implemented for this driver') - - def get_cluster(self, id): - """ - Get a cluster by ID - - :param id: The ID of the cluster to get - :type id: ``str`` - - :rtype: :class:`.ContainerCluster` - """ - raise NotImplementedError( - 'list_clusters not implemented for this driver')
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/__init__.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/__init__.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/docker.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/docker.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/docker.py deleted file mode 100644 index d7c8419..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/docker.py +++ /dev/null @@ -1,656 +0,0 @@ -# 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 -import datetime -import shlex -import re - -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.common.types import InvalidCredsError - -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 DockerResponse(JsonResponse): - - valid_response_codes = [httplib.OK, httplib.ACCEPTED, httplib.CREATED, - httplib.NO_CONTENT] - - def parse_body(self): - if len(self.body) == 0 and not self.parse_zero_length_body: - return self.body - - try: - # error responses are tricky in Docker. Eg response could be - # an error, but response status could still be 200 - content_type = self.headers.get('content-type', 'application/json') - if content_type == 'application/json' or content_type == '': - body = json.loads(self.body) - else: - body = self.body - except ValueError: - m = re.search('Error: (.+?)"', self.body) - if m: - error_msg = m.group(1) - raise Exception(error_msg) - else: - raise Exception( - 'ConnectionError: Failed to parse JSON response') - return body - - def parse_error(self): - if self.status == 401: - raise InvalidCredsError('Invalid credentials') - return self.body - - def success(self): - return self.status in self.valid_response_codes - - -class DockerException(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 "DockerException %s %s" % (self.code, self.message) - - -class DockerConnection(ConnectionUserAndKey): - - responseCls = DockerResponse - timeout = 60 - - 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' - if self.user_id and self.key: - user_b64 = base64.b64encode(b('%s:%s' % (self.user_id, self.key))) - headers['Authorization'] = 'Basic %s' % (user_b64.decode('utf-8')) - return headers - - -class DockerContainerDriver(ContainerDriver): - """ - Docker container driver class. - - >>> from libcloud.container.providers import get_driver - >>> driver = get_driver('docker') - >>> conn = driver(host='198.61.239.128', port=4243) - >>> conn.list_containers() - or connecting to http basic auth protected https host: - >>> conn = driver('user', 'pass', host='https://198.61.239.128', port=443) - - connect with tls authentication, by providing a hostname, port, a private - key file (.pem) and certificate (.pem) file - >>> conn = driver(host='https://198.61.239.128', - >>> port=4243, key_file='key.pem', cert_file='cert.pem') - """ - - type = Provider.DOCKER - name = 'Docker' - website = 'http://docker.io' - connectionCls = DockerConnection - supports_clusters = False - - def __init__(self, key=None, secret=None, secure=False, host='localhost', - port=4243, key_file=None, cert_file=None): - """ - :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. Note: Some providers - only support HTTPS, and it is on by default. - :type secure: ``bool`` - - :param host: Override hostname used for connections. - :type host: ``str`` - - :param port: Override port used for connections. - :type port: ``int`` - - :param key_file: Path to private key for TLS connection (optional) - :type key_file: ``str`` - - :param cert_file: Path to public key for TLS connection (optional) - :type cert_file: ``str`` - - :return: ``None`` - """ - super(DockerContainerDriver, self).__init__(key=key, secret=secret, - secure=secure, host=host, - port=port, - key_file=key_file, - cert_file=cert_file) - if host.startswith('https://'): - secure = True - - # strip the prefix - prefixes = ['http://', 'https://'] - for prefix in prefixes: - if host.startswith(prefix): - host = host.strip(prefix) - - if key_file or cert_file: - # docker tls authentication- - # https://docs.docker.com/articles/https/ - # We pass two files, a key_file with the - # private key and cert_file with the certificate - # libcloud will handle them through LibcloudHTTPSConnection - if not (key_file and cert_file): - raise Exception( - 'Needs both private key file and ' - 'certificate file for tls authentication') - self.connection.key_file = key_file - self.connection.cert_file = cert_file - self.connection.secure = True - else: - self.connection.secure = secure - - self.connection.host = host - self.connection.port = port - - def install_image(self, path): - """ - Install a container image from a remote path. - - :param path: Path to the container image - :type path: ``str`` - - :rtype: :class:`libcloud.container.base.ContainerImage` - """ - payload = { - } - data = json.dumps(payload) - - result = self.connection.request('/images/create?fromImage=%s' % - (path), data=data, method='POST') - if "errorDetail" in result.body: - raise DockerException(None, result.body) - try: - # get image id - image_id = re.findall( - r'{"status":"Download complete"' - r',"progressDetail":{},"id":"\w+"}', - result.body)[-1] - image_id = json.loads(image_id).get('id') - except: - raise DockerException(None, 'failed to install image') - - image = ContainerImage( - id=image_id, - name=path, - path=path, - version=None, - driver=self.connection.driver, - extra={}) - return image - - def list_images(self): - """ - List the installed container images - - :rtype: ``list`` of :class:`libcloud.container.base.ContainerImage` - """ - result = self.connection.request('/images/json').object - images = [] - for image in result: - try: - name = image.get('RepoTags')[0] - except: - name = image.get('Id') - images.append(ContainerImage( - id=image.get('Id'), - name=name, - path=name, - version=None, - driver=self.connection.driver, - extra={ - "created": image.get('Created'), - "size": image.get('Size'), - "virtual_size": image.get('VirtualSize'), - }, - )) - - return images - - def list_containers(self, image=None, all=True): - """ - List the deployed container images - - :param image: Filter to containers with a certain image - :type image: :class:`libcloud.container.base.ContainerImage` - - :param all: Show all container (including stopped ones) - :type all: ``bool`` - - :rtype: ``list`` of :class:`libcloud.container.base.Container` - """ - if all: - ex = '?all=1' - else: - ex = '' - try: - result = self.connection.request( - "/containers/json%s" % (ex)).object - except Exception as exc: - if hasattr(exc, 'errno') and exc.errno == 111: - raise DockerException( - exc.errno, - 'Make sure docker host is accessible' - 'and the API port is correct') - raise - - containers = [self._to_container(value) for value in result] - return containers - - def deploy_container(self, name, image, parameters=None, start=True, - command=None, hostname=None, user='', - stdin_open=True, tty=True, - mem_limit=0, ports=None, environment=None, dns=None, - volumes=None, volumes_from=None, - network_disabled=False, entrypoint=None, - cpu_shares=None, working_dir='', domainname=None, - memswap_limit=0, port_bindings=None): - """ - Deploy an installed container image - - For details on the additional parameters see : http://bit.ly/1PjMVKV - - :param name: The name of the new container - :type name: ``str`` - - :param image: The container image to deploy - :type image: :class:`libcloud.container.base.ContainerImage` - - :param parameters: Container Image parameters - :type parameters: ``str`` - - :param start: Start the container on deployment - :type start: ``bool`` - - :rtype: :class:`Container` - """ - command = shlex.split(str(command)) - if port_bindings is None: - port_bindings = {} - params = { - 'name': name - } - - payload = { - 'Hostname': hostname, - 'Domainname': domainname, - 'ExposedPorts': ports, - 'User': user, - 'Tty': tty, - 'OpenStdin': stdin_open, - 'StdinOnce': False, - 'Memory': mem_limit, - 'AttachStdin': True, - 'AttachStdout': True, - 'AttachStderr': True, - 'Env': environment, - 'Cmd': command, - 'Dns': dns, - 'Image': image.name, - 'Volumes': volumes, - 'VolumesFrom': volumes_from, - 'NetworkDisabled': network_disabled, - 'Entrypoint': entrypoint, - 'CpuShares': cpu_shares, - 'WorkingDir': working_dir, - 'MemorySwap': memswap_limit, - 'PublishAllPorts': True, - 'PortBindings': port_bindings, - } - - data = json.dumps(payload) - try: - result = self.connection.request('/containers/create', data=data, - params=params, method='POST') - except Exception as e: - if e.message.startswith('No such image:'): - raise DockerException(None, 'No such image: %s' % image.name) - else: - raise DockerException(None, e) - - id_ = result.object['Id'] - - payload = { - 'Binds': [], - 'PublishAllPorts': True, - 'PortBindings': port_bindings, - } - - data = json.dumps(payload) - if start: - result = self.connection.request( - '/containers/%s/start' % id_, data=data, - method='POST') - - return self.get_container(id_) - - def get_container(self, id): - """ - Get a container by ID - - :param id: The ID of the container to get - :type id: ``str`` - - :rtype: :class:`libcloud.container.base.Container` - """ - result = self.connection.request("/containers/%s/json" % - id).object - - return self._to_container(result) - - def start_container(self, container): - """ - Start a container - - :param container: The container to be started - :type container: :class:`libcloud.container.base.Container` - - :return: The container refreshed with current data - :rtype: :class:`libcloud.container.base.Container` - """ - payload = { - 'Binds': [], - 'PublishAllPorts': True, - } - data = json.dumps(payload) - result = self.connection.request( - '/containers/%s/start' % - (container.id), - method='POST', data=data) - if result.status in VALID_RESPONSE_CODES: - return self.get_container(container.id) - else: - raise DockerException(result.status, - 'failed to start container') - - 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('/containers/%s/stop' % - (container.id), - method='POST') - if result.status in VALID_RESPONSE_CODES: - return self.get_container(container.id) - else: - raise DockerException(result.status, - 'failed to stop container') - - def restart_container(self, container): - """ - Restart 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` - """ - data = json.dumps({'t': 10}) - # number of seconds to wait before killing the container - result = self.connection.request('/containers/%s/restart' % - (container.id), - data=data, method='POST') - if result.status in VALID_RESPONSE_CODES: - return self.get_container(container.id) - else: - raise DockerException(result.status, - 'failed to restart container') - - 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('/containers/%s' % (container.id), - method='DELETE') - return result.status in VALID_RESPONSE_CODES - - def ex_list_processes(self, container): - """ - List processes running inside a container - - :param container: The container to list processes for. - :type container: :class:`libcloud.container.base.Container` - - :rtype: ``str`` - """ - result = self.connection.request("/containers/%s/top" % - container.id).object - - return result - - def ex_rename_container(self, container, name): - """ - Rename a container - - :param container: The container to be renamed - :type container: :class:`libcloud.container.base.Container` - - :param name: The new name - :type name: ``str`` - - :rtype: :class:`libcloud.container.base.Container` - """ - result = self.connection.request('/containers/%s/rename?name=%s' - % (container.id, name), - method='POST') - if result.status in VALID_RESPONSE_CODES: - return self.get_container(container.id) - - def ex_get_logs(self, container, stream=False): - """ - Get container logs - - If stream == True, logs will be yielded as a stream - From Api Version 1.11 and above we need a GET request to get the logs - Logs are in different format of those of Version 1.10 and below - - :param container: The container to list logs for - :type container: :class:`libcloud.container.base.Container` - - :param stream: Stream the output - :type stream: ``bool`` - - :rtype: ``bool`` - """ - payload = {} - data = json.dumps(payload) - - if float(self._get_api_version()) > 1.10: - result = self.connection.request( - "/containers/%s/logs?follow=%s&stdout=1&stderr=1" % - (container.id, str(stream))).object - logs = result - else: - result = self.connection.request( - "/containers/%s/attach?logs=1&stream=%s&stdout=1&stderr=1" % - (container.id, str(stream)), method='POST', data=data) - logs = result.body - - return logs - - def ex_search_images(self, term): - """Search for an image on Docker.io. - Returns a list of ContainerImage objects - - >>> images = conn.ex_search_images(term='mistio') - >>> images - [<ContainerImage: id=rolikeusch/docker-mistio...>, - <ContainerImage: id=mist/mistio, name=mist/mistio, - driver=Docker ...>] - - :param term: The search term - :type term: ``str`` - - :rtype: ``list`` of :class:`libcloud.container.base.ContainerImage` - """ - - term = term.replace(' ', '+') - result = self.connection.request('/images/search?term=%s' % - term).object - images = [] - for image in result: - name = image.get('name') - images.append( - ContainerImage( - id=name, - path=name, - version=None, - name=name, - driver=self.connection.driver, - extra={ - "description": image.get('description'), - "is_official": image.get('is_official'), - "is_trusted": image.get('is_trusted'), - "star_count": image.get('star_count'), - }, - )) - - return images - - def ex_delete_image(self, image): - """ - Remove image from the filesystem - - :param image: The image to remove - :type image: :class:`libcloud.container.base.ContainerImage` - - :rtype: ``bool`` - """ - result = self.connection.request('/images/%s' % (image.name), - method='DELETE') - return result.status in VALID_RESPONSE_CODES - - def _to_container(self, data): - """ - Convert container in Container instances - """ - try: - name = data.get('Name').strip('/') - except: - try: - name = data.get('Names')[0].strip('/') - except: - name = data.get('Id') - state = data.get('State') - status = data.get('Status', - state.get('Status') - if state is not None else None) - if 'Exited' in status: - state = ContainerState.STOPPED - elif status.startswith('Up '): - state = ContainerState.RUNNING - else: - state = ContainerState.STOPPED - image = data.get('Image') - ports = data.get('Ports', []) - created = data.get('Created') - if isinstance(created, float): - created = ts_to_str(created) - extra = { - 'id': data.get('Id'), - 'status': data.get('Status'), - 'created': created, - 'image': image, - 'ports': ports, - 'command': data.get('Command'), - 'sizerw': data.get('SizeRw'), - 'sizerootfs': data.get('SizeRootFs'), - } - ips = [] - if ports is not None: - for port in ports: - if port.get('IP') is not None: - ips.append(port.get('IP')) - return Container( - id=data['Id'], - name=name, - image=ContainerImage( - id=data.get('ImageID', None), - path=image, - name=image, - version=None, - driver=self.connection.driver - ), - ip_addresses=ips, - state=state, - driver=self.connection.driver, - extra=extra) - - def _get_api_version(self): - """ - Get the docker API version information - """ - result = self.connection.request('/version').object - api_version = result.get('ApiVersion') - - return api_version - - -def ts_to_str(timestamp): - """ - Return a timestamp as a nicely formated datetime string. - """ - date = datetime.datetime.fromtimestamp(timestamp) - date_string = date.strftime("%d/%m/%Y %H:%M %Z") - return date_string http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/dummy.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/dummy.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/dummy.py deleted file mode 100644 index 2c99259..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/dummy.py +++ /dev/null @@ -1,46 +0,0 @@ -# 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. - -from libcloud.container.base import ContainerDriver - - -class DummyContainerDriver(ContainerDriver): - """ - Dummy Container driver. - - >>> from libcloud.container.drivers.dummy import DummyContainerDriver - >>> driver = DummyContainerDriver('key', 'secret') - >>> driver.name - 'Dummy Container Provider' - """ - - name = 'Dummy Container Provider' - website = 'http://example.com' - supports_clusters = False - - def __init__(self, api_key, api_secret): - """ - :param api_key: API key or username to used (required) - :type api_key: ``str`` - - :param api_secret: Secret password to be used (required) - :type api_secret: ``str`` - - :rtype: ``None`` - """ - -if __name__ == "__main__": - import doctest - doctest.testmod() http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/ecs.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/ecs.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/ecs.py deleted file mode 100644 index 36c5be3..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/ecs.py +++ /dev/null @@ -1,627 +0,0 @@ -# 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. - -try: - import simplejson as json -except ImportError: - import json - -from libcloud.container.base import (ContainerDriver, Container, - ContainerCluster, ContainerImage) -from libcloud.container.types import ContainerState -from libcloud.container.utils.docker import RegistryClient -from libcloud.common.aws import SignedAWSConnection, AWSJsonResponse - -__all__ = [ - 'ElasticContainerDriver' -] - - -ECS_VERSION = '2014-11-13' -ECR_VERSION = '2015-09-21' -ECS_HOST = 'ecs.%s.amazonaws.com' -ECR_HOST = 'ecr.%s.amazonaws.com' -ROOT = '/' -ECS_TARGET_BASE = 'AmazonEC2ContainerServiceV%s' % \ - (ECS_VERSION.replace('-', '')) -ECR_TARGET_BASE = 'AmazonEC2ContainerRegistry_V%s' % \ - (ECR_VERSION.replace('-', '')) - - -class ECSJsonConnection(SignedAWSConnection): - version = ECS_VERSION - host = ECS_HOST - responseCls = AWSJsonResponse - service_name = 'ecs' - - -class ECRJsonConnection(SignedAWSConnection): - version = ECR_VERSION - host = ECR_HOST - responseCls = AWSJsonResponse - service_name = 'ecr' - - -class ElasticContainerDriver(ContainerDriver): - name = 'Amazon Elastic Container Service' - website = 'https://aws.amazon.com/ecs/details/' - ecr_repository_host = '%s.dkr.ecr.%s.amazonaws.com' - connectionCls = ECSJsonConnection - ecrConnectionClass = ECRJsonConnection - supports_clusters = False - status_map = { - 'RUNNING': ContainerState.RUNNING - } - - def __init__(self, access_id, secret, region): - super(ElasticContainerDriver, self).__init__(access_id, secret) - self.region = region - self.region_name = region - self.connection.host = ECS_HOST % (region) - - # Setup another connection class for ECR - conn_kwargs = self._ex_connection_class_kwargs() - self.ecr_connection = self.ecrConnectionClass( - access_id, secret, **conn_kwargs) - self.ecr_connection.host = ECR_HOST % (region) - self.ecr_connection.driver = self - self.ecr_connection.connect() - - def _ex_connection_class_kwargs(self): - return {'signature_version': '4'} - - def list_images(self, ex_repository_name): - """ - List the images in an ECR repository - - :param ex_repository_name: The name of the repository to check - defaults to the default repository. - :type ex_repository_name: ``str`` - - :return: a list of images - :rtype: ``list`` of :class:`libcloud.container.base.ContainerImage` - """ - request = {} - request['repositoryName'] = ex_repository_name - list_response = self.ecr_connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_ecr_headers('ListImages') - ).object - repository_id = self.ex_get_repository_id(ex_repository_name) - host = self._get_ecr_host(repository_id) - return self._to_images(list_response['imageIds'], - host, - ex_repository_name) - - def list_clusters(self): - """ - Get a list of potential locations to deploy clusters into - - :param location: The location to search in - :type location: :class:`libcloud.container.base.ClusterLocation` - - :rtype: ``list`` of :class:`libcloud.container.base.ContainerCluster` - """ - listdata = self.connection.request( - ROOT, - method='POST', - data=json.dumps({}), - headers=self._get_headers('ListClusters') - ).object - request = {'clusters': listdata['clusterArns']} - data = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('DescribeClusters') - ).object - return self._to_clusters(data) - - def create_cluster(self, name, location=None): - """ - Create a container cluster - - :param name: The name of the cluster - :type name: ``str`` - - :param location: The location to create the cluster in - :type location: :class:`libcloud.container.base.ClusterLocation` - - :rtype: :class:`libcloud.container.base.ContainerCluster` - """ - request = {'clusterName': name} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('CreateCluster') - ).object - return self._to_cluster(response['cluster']) - - def destroy_cluster(self, cluster): - """ - Delete a cluster - - :return: ``True`` if the destroy was successful, otherwise ``False``. - :rtype: ``bool`` - """ - request = {'cluster': cluster.id} - data = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('DeleteCluster') - ).object - return data['cluster']['status'] == 'INACTIVE' - - def list_containers(self, image=None, cluster=None): - """ - List the deployed container images - - :param image: Filter to containers with a certain image - :type image: :class:`libcloud.container.base.ContainerImage` - - :param cluster: Filter to containers in a cluster - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :rtype: ``list`` of :class:`libcloud.container.base.Container` - """ - request = {'cluster': 'default'} - if cluster is not None: - request['cluster'] = cluster.id - if image is not None: - request['family'] = image.name - list_response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('ListTasks') - ).object - if len(list_response['taskArns']) == 0: - return [] - containers = self.ex_list_containers_for_task( - list_response['taskArns']) - return containers - - def deploy_container(self, name, image, cluster=None, - parameters=None, start=True, ex_cpu=10, ex_memory=500, - ex_container_port=None, ex_host_port=None): - """ - Creates a task definition from a container image that can be run - in a cluster. - - :param name: The name of the new container - :type name: ``str`` - - :param image: The container image to deploy - :type image: :class:`libcloud.container.base.ContainerImage` - - :param cluster: The cluster to deploy to, None is default - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :param parameters: Container Image parameters - :type parameters: ``str`` - - :param start: Start the container on deployment - :type start: ``bool`` - - :rtype: :class:`libcloud.container.base.Container` - """ - data = {} - if ex_container_port is None and ex_host_port is None: - port_maps = [] - else: - port_maps = [ - { - "containerPort": ex_container_port, - "hostPort": ex_host_port - } - ] - data['containerDefinitions'] = [ - { - "mountPoints": [], - "name": name, - "image": image.name, - "cpu": ex_cpu, - "environment": [], - "memory": ex_memory, - "portMappings": port_maps, - "essential": True, - "volumesFrom": [] - } - ] - data['family'] = name - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(data), - headers=self._get_headers('RegisterTaskDefinition') - ).object - if start: - return self.ex_start_task( - response['taskDefinition']['taskDefinitionArn'])[0] - else: - return Container( - id=None, - name=name, - image=image, - state=ContainerState.RUNNING, - ip_addresses=[], - extra={ - 'taskDefinitionArn': - response['taskDefinition']['taskDefinitionArn'] - }, - driver=self.connection.driver - ) - - def get_container(self, id): - """ - Get a container by ID - - :param id: The ID of the container to get - :type id: ``str`` - - :rtype: :class:`libcloud.container.base.Container` - """ - containers = self.ex_list_containers_for_task([id]) - return containers[0] - - def start_container(self, container, count=1): - """ - Start a deployed task - - :param container: The container to start - :type container: :class:`libcloud.container.base.Container` - - :param count: Number of containers to start - :type count: ``int`` - - :rtype: :class:`libcloud.container.base.Container` - """ - return self.ex_start_task(container.extra['taskDefinitionArn'], count) - - def stop_container(self, container): - """ - Stop a deployed container - - :param container: The container to stop - :type container: :class:`libcloud.container.base.Container` - - :rtype: :class:`libcloud.container.base.Container` - """ - request = {'task': container.extra['taskArn']} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('StopTask') - ).object - containers = [] - containers.extend(self._to_containers( - response['task'], - container.extra['taskDefinitionArn'])) - return containers - - def restart_container(self, container): - """ - Restart a deployed container - - :param container: The container to restart - :type container: :class:`libcloud.container.base.Container` - - :rtype: :class:`libcloud.container.base.Container` - """ - self.stop_container(container) - return self.start_container(container) - - def destroy_container(self, container): - """ - Destroy a deployed container - - :param container: The container to destroy - :type container: :class:`libcloud.container.base.Container` - - :rtype: :class:`libcloud.container.base.Container` - """ - return self.stop_container(container) - - def ex_start_task(self, task_arn, count=1): - """ - Run a task definition and get the containers - - :param task_arn: The task ARN to Run - :type task_arn: ``str`` - - :param count: The number of containers to start - :type count: ``int`` - - :rtype: ``list`` of :class:`libcloud.container.base.Container` - """ - request = None - request = {'count': count, - 'taskDefinition': task_arn} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('RunTask') - ).object - containers = [] - for task in response['tasks']: - containers.extend(self._to_containers(task, task_arn)) - return containers - - def ex_list_containers_for_task(self, task_arns): - """ - Get a list of containers by ID collection (ARN) - - :param task_arns: The list of ARNs - :type task_arns: ``list`` of ``str`` - - :rtype: ``list`` of :class:`libcloud.container.base.Container` - """ - describe_request = {'tasks': task_arns} - descripe_response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(describe_request), - headers=self._get_headers('DescribeTasks') - ).object - containers = [] - for task in descripe_response['tasks']: - containers.extend(self._to_containers( - task, task['taskDefinitionArn'])) - return containers - - def ex_create_service(self, name, cluster, - task_definition, desired_count=1): - """ - Runs and maintains a desired number of tasks from a specified - task definition. If the number of tasks running in a service - drops below desired_count, Amazon ECS spawns another - instantiation of the task in the specified cluster. - - :param name: the name of the service - :type name: ``str`` - - :param cluster: The cluster to run the service on - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :param task_definition: The task definition name or ARN for the - service - :type task_definition: ``str`` - - :param desired_count: The desired number of tasks to be running - at any one time - :type desired_count: ``int`` - - :rtype: ``object`` The service object - """ - request = { - 'serviceName': name, - 'taskDefinition': task_definition, - 'desiredCount': desired_count, - 'cluster': cluster.id} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('CreateService') - ).object - return response['service'] - - def ex_list_service_arns(self, cluster=None): - """ - List the services - - :param cluster: The cluster hosting the services - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :rtype: ``list`` of ``str`` - """ - request = {} - if cluster is not None: - request['cluster'] = cluster.id - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('ListServices') - ).object - return response['serviceArns'] - - def ex_describe_service(self, service_arn): - """ - Get the details of a service - - :param cluster: The hosting cluster - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :param service_arn: The service ARN to describe - :type service_arn: ``str`` - - :return: The service object - :rtype: ``object`` - """ - request = {'services': [service_arn]} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('DescribeServices') - ).object - return response['services'][0] - - def ex_destroy_service(self, service_arn): - """ - Deletes a service - - :param cluster: The target cluster - :type cluster: :class:`libcloud.container.base.ContainerCluster` - - :param service_arn: The service ARN to destroy - :type service_arn: ``str`` - """ - request = { - 'service': service_arn} - response = self.connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_headers('DeleteService') - ).object - return response['service'] - - def ex_get_registry_client(self, repository_name): - """ - Get a client for an ECR repository - - :param repository_name: The unique name of the repository - :type repository_name: ``str`` - - :return: a docker registry API client - :rtype: :class:`libcloud.container.utils.docker.RegistryClient` - """ - repository_id = self.ex_get_repository_id(repository_name) - token = self.ex_get_repository_token(repository_id) - host = self._get_ecr_host(repository_id) - return RegistryClient( - host=host, - username='AWS', - password=token - ) - - def ex_get_repository_token(self, repository_id): - """ - Get the authorization token (12 hour expiry) for a repository - - :param repository_id: The ID of the repository - :type repository_id: ``str`` - - :return: A token for login - :rtype: ``str`` - """ - request = {'RegistryIds': [repository_id]} - response = self.ecr_connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_ecr_headers('GetAuthorizationToken') - ).object - return response['authorizationData'][0]['authorizationToken'] - - def ex_get_repository_id(self, repository_name): - """ - Get the ID of a repository - - :param repository_name: The unique name of the repository - :type repository_name: ``str`` - - :return: The repository ID - :rtype: ``str`` - """ - request = {'repositoryNames': [repository_name]} - list_response = self.ecr_connection.request( - ROOT, - method='POST', - data=json.dumps(request), - headers=self._get_ecr_headers('DescribeRepositories') - ).object - repository_id = list_response['repositories'][0]['registryId'] - return repository_id - - def _get_ecr_host(self, repository_id): - return self.ecr_repository_host % ( - repository_id, - self.region) - - def _get_headers(self, action): - """ - Get the default headers for a request to the ECS API - """ - return {'x-amz-target': '%s.%s' % - (ECS_TARGET_BASE, action), - 'Content-Type': 'application/x-amz-json-1.1' - } - - def _get_ecr_headers(self, action): - """ - Get the default headers for a request to the ECR API - """ - return {'x-amz-target': '%s.%s' % - (ECR_TARGET_BASE, action), - 'Content-Type': 'application/x-amz-json-1.1' - } - - def _to_clusters(self, data): - clusters = [] - for cluster in data['clusters']: - clusters.append(self._to_cluster(cluster)) - return clusters - - def _to_cluster(self, data): - return ContainerCluster( - id=data['clusterArn'], - name=data['clusterName'], - driver=self.connection.driver - ) - - def _to_containers(self, data, task_definition_arn): - clusters = [] - for cluster in data['containers']: - clusters.append(self._to_container(cluster, task_definition_arn)) - return clusters - - def _to_container(self, data, task_definition_arn): - return Container( - id=data['containerArn'], - name=data['name'], - image=ContainerImage( - id=None, - name=data['name'], - path=None, - version=None, - driver=self.connection.driver - ), - ip_addresses=None, - state=self.status_map.get(data['lastStatus'], None), - extra={ - 'taskArn': data['taskArn'], - 'taskDefinitionArn': task_definition_arn - }, - driver=self.connection.driver - ) - - def _to_images(self, data, host, repository_name): - images = [] - for image in data: - images.append(self._to_image(image, host, repository_name)) - return images - - def _to_image(self, data, host, repository_name): - path = '%s/%s:%s' % ( - host, - repository_name, - data['imageTag'] - ) - return ContainerImage( - id=None, - name=path, - path=path, - version=data['imageTag'], - driver=self.connection.driver - ) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/joyent.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/joyent.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/joyent.py deleted file mode 100644 index 39df019..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/joyent.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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. - - -from libcloud.container.providers import Provider - -from libcloud.container.drivers.docker import (DockerContainerDriver, - DockerConnection) - - -class JoyentContainerDriver(DockerContainerDriver): - """ - Joyent Triton container driver class. - - >>> from libcloud.container.providers import get_driver - >>> driver = get_driver('joyent') - >>> conn = driver(host='https://us-east-1.docker.joyent.com', - port=2376, key_file='key.pem', cert_file='cert.pem') - """ - - type = Provider.JOYENT - name = 'Joyent Triton' - website = 'http://joyent.com' - connectionCls = DockerConnection - supports_clusters = False - - def __init__(self, key=None, secret=None, secure=False, host='localhost', - port=2376, key_file=None, cert_file=None): - - super(JoyentContainerDriver, self).__init__(key=key, secret=secret, - secure=secure, host=host, - port=port, - key_file=key_file, - cert_file=cert_file) - if host.startswith('https://'): - secure = True - - # strip the prefix - prefixes = ['http://', 'https://'] - for prefix in prefixes: - if host.startswith(prefix): - host = host.strip(prefix) - - if key_file or cert_file: - # docker tls authentication- - # https://docs.docker.com/articles/https/ - # We pass two files, a key_file with the - # private key and cert_file with the certificate - # libcloud will handle them through LibcloudHTTPSConnection - if not (key_file and cert_file): - raise Exception( - 'Needs both private key file and ' - 'certificate file for tls authentication') - self.connection.key_file = key_file - self.connection.cert_file = cert_file - self.connection.secure = True - else: - self.connection.secure = secure - - self.connection.host = host - self.connection.port = port http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/drivers/kubernetes.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/kubernetes.py b/apache-libcloud-1.0.0rc2/libcloud/container/drivers/kubernetes.py deleted file mode 100644 index 426a5ef..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/drivers/kubernetes.py +++ /dev/null @@ -1,405 +0,0 @@ -# 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 -import datetime - -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.common.types import InvalidCredsError - -from libcloud.container.base import (Container, ContainerDriver, - ContainerImage, ContainerCluster) - -from libcloud.container.providers import Provider -from libcloud.container.types import ContainerState - - -VALID_RESPONSE_CODES = [httplib.OK, httplib.ACCEPTED, httplib.CREATED, - httplib.NO_CONTENT] - -ROOT_URL = '/api/' - - -class KubernetesResponse(JsonResponse): - - valid_response_codes = [httplib.OK, httplib.ACCEPTED, httplib.CREATED, - httplib.NO_CONTENT] - - def parse_error(self): - if self.status == 401: - raise InvalidCredsError('Invalid credentials') - return self.body - - def success(self): - return self.status in self.valid_response_codes - - -class KubernetesException(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 "KubernetesException %s %s" % (self.code, self.message) - - -class KubernetesConnection(ConnectionUserAndKey): - responseCls = KubernetesResponse - timeout = 60 - - 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' - if self.key and self.secret: - user_b64 = base64.b64encode(b('%s:%s' % (self.key, self.secret))) - headers['Authorization'] = 'Basic %s' % (user_b64.decode('utf-8')) - return headers - - -class KubernetesPod(object): - def __init__(self, name, containers, namespace): - """ - A Kubernetes pod - """ - self.name = name - self.containers = containers - self.namespace = namespace - - -class KubernetesContainerDriver(ContainerDriver): - type = Provider.KUBERNETES - name = 'Kubernetes' - website = 'http://kubernetes.io' - connectionCls = KubernetesConnection - supports_clusters = True - - def __init__(self, key=None, secret=None, secure=False, host='localhost', - port=4243): - """ - :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. Note: Some providers - only support HTTPS, and it is on by default. - :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`` - """ - super(KubernetesContainerDriver, self).__init__(key=key, secret=secret, - secure=secure, - host=host, - port=port) - if host.startswith('https://'): - secure = True - - # strip the prefix - prefixes = ['http://', 'https://'] - for prefix in prefixes: - if host.startswith(prefix): - host = host.strip(prefix) - - self.connection.secure = secure - self.connection.key = key - self.connection.secret = secret - - self.connection.host = host - self.connection.port = port - - def list_containers(self, image=None, all=True): - """ - List the deployed container images - - :param image: Filter to containers with a certain image - :type image: :class:`libcloud.container.base.ContainerImage` - - :param all: Show all container (including stopped ones) - :type all: ``bool`` - - :rtype: ``list`` of :class:`libcloud.container.base.Container` - """ - try: - result = self.connection.request( - ROOT_URL + "v1/pods").object - except Exception as exc: - if hasattr(exc, 'errno') and exc.errno == 111: - raise KubernetesException( - exc.errno, - 'Make sure kube host is accessible' - 'and the API port is correct') - raise - - pods = [self._to_pod(value) for value in result['items']] - containers = [] - for pod in pods: - containers.extend(pod.containers) - return containers - - def get_container(self, id): - """ - Get a container by ID - - :param id: The ID of the container to get - :type id: ``str`` - - :rtype: :class:`libcloud.container.base.Container` - """ - result = self.connection.request(ROOT_URL + "v1/nodes/%s" % - id).object - - return self._to_container(result) - - def list_clusters(self): - """ - Get a list of namespaces that pods can be deployed into - - :param location: The location to search in - :type location: :class:`libcloud.container.base.ClusterLocation` - - :rtype: ``list`` of :class:`libcloud.container.base.ContainerCluster` - """ - try: - result = self.connection.request( - ROOT_URL + "v1/namespaces/").object - except Exception as exc: - if hasattr(exc, 'errno') and exc.errno == 111: - raise KubernetesException( - exc.errno, - 'Make sure kube host is accessible' - 'and the API port is correct') - raise - - clusters = [self._to_cluster(value) for value in result['items']] - return clusters - - def get_cluster(self, id): - """ - Get a cluster by ID - - :param id: The ID of the cluster to get - :type id: ``str`` - - :rtype: :class:`libcloud.container.base.ContainerCluster` - """ - result = self.connection.request(ROOT_URL + "v1/namespaces/%s" % - id).object - - return self._to_cluster(result) - - def destroy_cluster(self, cluster): - """ - Delete a cluster (namespace) - - :return: ``True`` if the destroy was successful, otherwise ``False``. - :rtype: ``bool`` - """ - self.connection.request(ROOT_URL + "v1/namespaces/%s" % - cluster.id, method='DELETE').object - return True - - def create_cluster(self, name, location=None): - """ - Create a container cluster (a namespace) - - :param name: The name of the cluster - :type name: ``str`` - - :param location: The location to create the cluster in - :type location: :class:`.ClusterLocation` - - :rtype: :class:`.ContainerCluster` - """ - request = { - 'metadata': { - 'name': name - } - } - result = self.connection.request(ROOT_URL + "v1/namespaces", - method='POST', - data=json.dumps(request)).object - return self._to_cluster(result) - - def deploy_container(self, name, image, cluster=None, - parameters=None, start=True): - """ - Deploy an installed container image. - In kubernetes this deploys a single container Pod. - https://cloud.google.com/container-engine/docs/pods/single-container - - :param name: The name of the new container - :type name: ``str`` - - :param image: The container image to deploy - :type image: :class:`.ContainerImage` - - :param cluster: The cluster to deploy to, None is default - :type cluster: :class:`.ContainerCluster` - - :param parameters: Container Image parameters - :type parameters: ``str`` - - :param start: Start the container on deployment - :type start: ``bool`` - - :rtype: :class:`.Container` - """ - if cluster is None: - namespace = 'default' - else: - namespace = cluster.id - request = { - "metadata": { - "name": name - }, - "spec": { - "containers": [ - { - "name": name, - "image": image.name - } - ] - } - } - result = self.connection.request(ROOT_URL + "v1/namespaces/%s/pods" - % namespace, - method='POST', - data=json.dumps(request)).object - return self._to_cluster(result) - - def destroy_container(self, container): - """ - Destroy a deployed container. Because the containers are single - container pods, this will delete the pod. - - :param container: The container to destroy - :type container: :class:`.Container` - - :rtype: ``bool`` - """ - return self.ex_delete_pod(container.extra['namespace'], - container.extra['pod']) - - def ex_list_pods(self): - """ - List available Pods - - :rtype: ``list`` of :class:`.KubernetesPod` - """ - result = self.connection.request(ROOT_URL + "v1/pods").object - return [self._to_pod(value) for value in result['items']] - - def ex_destroy_pod(self, namespace, pod_name): - """ - Delete a pod and the containers within it. - """ - self.connection.request( - ROOT_URL + "v1/namespaces/%s/pods/%s" % ( - namespace, pod_name), - method='DELETE').object - return True - - def _to_pod(self, data): - """ - Convert an API response to a Pod object - """ - container_statuses = data['status']['containerStatuses'] - containers = [] - # response contains the status of the containers in a separate field - for container in data['spec']['containers']: - spec = list(filter(lambda i: i['name'] == container['name'], - container_statuses))[0] - containers.append( - self._to_container(container, spec, data) - ) - return KubernetesPod( - name=data['metadata']['name'], - namespace=data['metadata']['namespace'], - containers=containers) - - def _to_container(self, data, container_status, pod_data): - """ - Convert container in Container instances - """ - return Container( - id=container_status['containerID'], - name=data['name'], - image=ContainerImage( - id=container_status['imageID'], - name=data['image'], - path=None, - version=None, - driver=self.connection.driver), - ip_addresses=None, - state=ContainerState.RUNNING, - driver=self.connection.driver, - extra={ - 'pod': pod_data['metadata']['name'], - 'namespace': pod_data['metadata']['namespace'] - }) - - def _to_cluster(self, data): - """ - Convert namespace to a cluster - """ - metadata = data['metadata'] - status = data['status'] - return ContainerCluster( - id=metadata['name'], - name=metadata['name'], - driver=self.connection.driver, - extra={'phase': status['phase']}) - - def _get_api_version(self): - """ - Get the docker API version information - """ - result = self.connection.request('/version').object - api_version = result.get('ApiVersion') - - return api_version - - -def ts_to_str(timestamp): - """ - Return a timestamp as a nicely formated datetime string. - """ - date = datetime.datetime.fromtimestamp(timestamp) - date_string = date.strftime("%d/%m/%Y %H:%M %Z") - return date_string http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/providers.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/providers.py b/apache-libcloud-1.0.0rc2/libcloud/container/providers.py deleted file mode 100644 index 16ab58c..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/providers.py +++ /dev/null @@ -1,40 +0,0 @@ -# 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. - -from libcloud.container.types import Provider -from libcloud.common.providers import get_driver as _get_provider_driver -from libcloud.common.providers import set_driver as _set_provider_driver - -DRIVERS = { - Provider.DUMMY: - ('libcloud.container.drivers.dummy', 'DummyContainerDriver'), - Provider.DOCKER: - ('libcloud.container.drivers.docker', 'DockerContainerDriver'), - Provider.JOYENT: - ('libcloud.container.drivers.joyent', 'JoyentContainerDriver'), - Provider.ECS: - ('libcloud.container.drivers.ecs', 'ElasticContainerDriver'), - Provider.KUBERNETES: - ('libcloud.container.drivers.kubernetes', 'KubernetesContainerDriver'), -} - - -def get_driver(provider): - return _get_provider_driver(drivers=DRIVERS, provider=provider) - - -def set_driver(provider, module, klass): - return _set_provider_driver(drivers=DRIVERS, provider=provider, - module=module, klass=klass) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/types.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/types.py b/apache-libcloud-1.0.0rc2/libcloud/container/types.py deleted file mode 100644 index 263d9d4..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/container/types.py +++ /dev/null @@ -1,76 +0,0 @@ -# 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. - -__all__ = [ - 'Provider', - 'ContainerState' -] - - -class Type(object): - @classmethod - def tostring(cls, value): - """Return the string representation of the state object attribute - :param str value: the state object to turn into string - :return: the uppercase string that represents the state object - :rtype: str - """ - return value.upper() - - @classmethod - def fromstring(cls, value): - """Return the state object attribute that matches the string - :param str value: the string to look up - :return: the state object attribute that matches the string - :rtype: str - """ - return getattr(cls, value.upper(), None) - - -class Provider(object): - DUMMY = 'dummy' - DOCKER = 'docker' - JOYENT = 'joyent' - ECS = 'ecs' - KUBERNETES = 'kubernetes' - - -class ContainerState(Type): - """ - Standard states for a container - - :cvar RUNNING: Container is running. - :cvar REBOOTING: Container is rebooting. - :cvar TERMINATED: Container is terminated. - This container can't be started later on. - :cvar STOPPED: Container is stopped. - This container can be started later on. - :cvar PENDING: Container is pending. - :cvar SUSPENDED: Container is suspended. - :cvar ERROR: Container is an error state. - Usually no operations can be performed - on the container once it ends up in the error state. - :cvar PAUSED: Container is paused. - :cvar UNKNOWN: Container state is unknown. - """ - RUNNING = 'running' - REBOOTING = 'rebooting' - TERMINATED = 'terminated' - PENDING = 'pending' - UNKNOWN = 'unknown' - STOPPED = 'stopped' - SUSPENDED = 'suspended' - ERROR = 'error' - PAUSED = 'paused' http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/container/utils/__init__.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/container/utils/__init__.py b/apache-libcloud-1.0.0rc2/libcloud/container/utils/__init__.py deleted file mode 100644 index e69de29..0000000
