예제 #1
0
    def __init__(self, config_file):
        import uuid
        import kubernetes

        super(KubernetesContainer, self).__init__()

        if "KUBERNETES_SERVICE_PORT" in os.environ:
            kubernetes.config.load_incluster_config()
        else:
            kubernetes.config.load_kube_config()

        self.env_ = []
        self.secrets_ = []
        self.config_file_ = config_file
        self.apps_api_ = kubernetes.client.AppsV1Api()
        self.core_api_ = kubernetes.client.CoreV1Api()
        self.ext_api_ = kubernetes.client.ApiextensionsV1beta1Api()
        self.obj_api_ = kubernetes.client.CustomObjectsApi()
        self.namespace_ = Environment.get("kubernetes.namespace")
        self.port_ = None
        self.deploymentName_ = "ibm-app-gw-{0}".format(uuid.uuid1())
        self.configmapName_ = "ibm-app-gw.config.{0}".format(uuid.uuid1())
        self.useCRD_ = self.useCRD()

        logger.info(
            "Using a kubernetes public IP of {0}.  Use the "
            "kubernetes.ip configuration entry to change the IP to suit "
            "your environment.".format(Environment.get("kubernetes.ip")))
예제 #2
0
    def __init__(self, config_file=None):
        """
        Initialize this class.  Note that a VersionException will be raised
        if the version number contained within the configuration file is
        greater than the version number of the requested IBM Application
        Gateway image.
        """

        super(Container, self).__init__()

        # If a configuration file is specified we need to ensure that the
        # IAG version supports the version of the specified configuration
        # file.
        if config_file is not None:
            with open(config_file, 'r') as stream:
                data = yaml.safe_load(stream)

                if data['version'] > Environment().get("image.tag"):
                    raise VersionException(
                        "The configuration file is not supported "
                        "with the specified image version: {0}".format(
                            Environment().get("image.tag")))

        if run_kubernetes():
            self.client_ = KubernetesContainer(config_file)
        else:
            self.client_ = DockerContainer(config_file=config_file)
예제 #3
0
    def startContainer(self, image):
        """
        The following command is used to start the IBM Application Gateway
        container using the supplied configuration.
        """

        if self.container_ is not None:
            logger.critical(
                "A container has already been started in this object.")

            raise Exception(
                "A container has already been started in this object.")

        volumes = []

        if Environment.is_container_context():
            volumes = {
                Environment.get("docker.volume_name"): {
                    "bind": Container.config_volume_path,
                    "mode": "rw"
                }
            }
        elif self.cfgFile_ is not None:
            volumes = [
                "{0}:{1}/config.yaml".format(self.cfgFile_,
                                             Container.config_volume_path)
            ]

        self.container_ = self.client_.containers.run(image,
                                                      auto_remove=True,
                                                      environment=self.env_,
                                                      detach=True,
                                                      publish_all_ports=True,
                                                      volumes=volumes)
    def write(self, filename=None):
        """
        Write the current configuration as a yaml file which can be used by
        the container.

        @param filename : The name of the file to write.  If no file is
                          specified a temporary file will be created.

        @retval The name of the file which has been written.
        """

        data = self.toYaml()

        # If we have not been provided with a file name we create a file name
        # now.
        if filename is None:
            dir = Container.config_volume_path \
                    if Environment.is_container_context() else None

            fd, filename = mkstemp(suffix=".yml", dir=dir)

            if Environment.is_container_context():
                os.fchown(fd, Environment.iag_user, Environment.iag_group)

            os.close(fd)

        # Write the data.
        with open(filename, 'w') as outfile:
            yaml.dump(data, outfile, width=float("inf"))

        logger.info("Wrote the IBM Application Gateway configuration to {0}".\
                format(filename))

        return filename
예제 #5
0
    def startContainer(self, removeAtExit=True, protocol="https"):
        """
        The following command is used to start the IBM Application Gateway
        container using the supplied configuration.

        removeAtExit: should the container be automatically removed when the
                      script exits?
        """

        image = "{0}:{1}".format(Environment().get("image.name"),
                                 Environment().get("image.tag"))

        logger.info("Starting the container from {0}".format(image))

        logger.info("Protocol to start {0}".format(protocol))

        self.client_.startContainer(image)

        if removeAtExit:
            atexit.register(self.stopContainer)

        # Wait for the container to become healthy.  We should really be using
        # the health of the container, but this takes a while to kick in.  So,
        # we instead poll the https port of the server until we make a
        # successful SSL connection.

        running = False
        attempt = 0

        while not running and attempt < 30:
            time.sleep(1)

            try:
                logger.info("Protocol in loop {0}".format(protocol))
                logger.info("Port in loop {0}".format(self.port(protocol)))
                logger.info("IP in loop {0}".format(self.ipaddr()))
                requests.get("{0}://{1}:{2}".format(protocol, self.ipaddr(),
                                                    self.port(protocol)),
                             verify=False,
                             allow_redirects=False,
                             timeout=2)

                running = True
            except:
                self.client_.reload()
                attempt += 1

        if not running:
            message = "The container failed to start within the allocated time."
            logger.critical(message)

            logger.critical(self.client_.container_.logs())

            raise Exception(message)

        logger.info("The container has started")
예제 #6
0
    def ipaddr(self, protocol="https"):
        """
        Retrieve the IP address which can be used to access the container.
        """

        if self.container_ is None:
            logger.critical("Error> the container is not currently running!")

            raise Exception("The container is not currently running!")

        if protocol == "https":
            port = "8443/tcp"
        elif protocol == "http":
            port = "8080/tcp"
        else:
            logger.critical("Error> an invalid protocol was specified!")

            raise Exception("An invalid protocol was specified!")

        ipaddr = self.container_.attrs['NetworkSettings']['Ports'][port]\
                [0]['HostIp']

        if ipaddr == "0.0.0.0":
            ipaddr = Environment.get("docker.ip")

        return ipaddr
예제 #7
0
    def ipaddr(self, protocol="https"):
        """
        Retrieve the IP address which can be used to access the container.
        """

        if self.port_ is None:
            logger.critical("Error> the container is not currently running!")

            raise Exception("The container is not currently running!")

        return self.deploymentName_ if "KUBERNETES_SERVICE_PORT" in os.environ \
                else Environment.get("kubernetes.ip")
예제 #8
0
    def __createDeploymentObject(self, image):
        """
        Create the deployment object for the IBM Application Gateway.
        """

        import kubernetes

        # If a configuration file has been specified we want to mount the
        # configmap.
        volumes = []
        volume_mounts = []

        if self.config_file_ is not None:
            if self.useCRD_:
                self.setEnv("CONFIG_CUSTOM_OBJECT_NAME", self.configmapName_)
            else:
                volumes.append(
                    kubernetes.client.V1Volume(
                        config_map=kubernetes.client.V1ConfigMapVolumeSource(
                            items=[
                                kubernetes.client.V1KeyToPath(
                                    path="config.yaml",
                                    key=self.__config_map_key)
                            ],
                            name=self.configmapName_),
                        name=self.deploymentName_))

                volume_mounts.append(
                    kubernetes.client.V1VolumeMount(
                        mount_path=Container.config_volume_path,
                        name=self.deploymentName_))

        # Create the pod template container
        container = kubernetes.client.V1Container(
            name=self.deploymentName_,
            image=image,
            ports=[
                kubernetes.client.V1ContainerPort(container_port=8443,
                                                  name="https"),
                kubernetes.client.V1ContainerPort(container_port=8080,
                                                  name="http")
            ],
            env=self.env_,
            volume_mounts=volume_mounts,
            env_from=self.secrets_)

        # Create the secret which is used when pulling the IAG image.
        secret = kubernetes.client.V1LocalObjectReference(
            name=Environment.get("kubernetes.image_pull_secret"))

        # Create and configurate a spec section
        template = kubernetes.client.V1PodTemplateSpec(
            metadata=kubernetes.client.V1ObjectMeta(
                labels={"app": self.deploymentName_}),
            spec=kubernetes.client.V1PodSpec(containers=[container],
                                             image_pull_secrets=[secret],
                                             volumes=volumes))

        # Create the specification of the deployment
        spec = kubernetes.client.V1DeploymentSpec(
            replicas=1,
            template=template,
            selector={'matchLabels': {
                'app': self.deploymentName_
            }})

        # Instantiate the deployment object
        deployment = kubernetes.client.V1Deployment(
            api_version="apps/v1",
            kind="Deployment",
            metadata=kubernetes.client.V1ObjectMeta(name=self.deploymentName_),
            spec=spec)

        return deployment