def test_connection(self): """ Test connection to OpenShift server Raises: ProviderFailedException - Invalid SSL/TLS certificate """ logger.debug("Testing connection to OpenShift server") if self.provider_ca and not os.path.exists(self.provider_ca): raise ProviderFailedException("Unable to find CA path %s" % self.provider_ca) try: (status_code, return_data) = \ Utils.make_rest_request("get", self.openshift_api, verify=self._requests_tls_verify()) except SSLError as e: if self.provider_tls_verify: msg = "SSL/TLS ERROR: invalid certificate. " \ "Add certificate of correct Certificate Authority providing" \ " `%s` or you can disable SSL/TLS verification by `%s=False`" \ % (PROVIDER_CA_KEY, PROVIDER_TLS_VERIFY_KEY) raise ProviderFailedException(msg) else: # this shouldn't happen raise ProviderFailedException(e.message)
def get_pod_status(self, namespace, pod): """ Get pod status. Args: namespace (str): Openshift namespace pod (str): Pod name Returns: Status of pod (str) Raises: ProviderFailedException when unable to fetch Pod status. """ args = { 'namespace': namespace, 'pod': pod, 'access_token': self.access_token } url = urljoin( self.kubernetes_api, 'namespaces/{namespace}/pods/{pod}?' 'access_token={access_token}'.format(**args)) (status_code, return_data) = \ Utils.make_rest_request("get", url, verify=self._requests_tls_verify()) if status_code != 200: raise ProviderFailedException( 'Could not fetch status for pod: {namespace}/{pod}'.format( namespace=namespace, pod=pod)) return return_data['status']['phase'].lower()
def stop(self): """ Undeploys the app by given resource manifests. Undeploy operation deletes Marathon apps from cluster. """ for artifact in self.marathon_artifacts: url = urlparse.urljoin( self.marathon_api, "apps/%s" % artifact["id"]) if self.dryrun: logger.info("DRY-RUN: %s", url) continue logger.debug("Deleting appid: %s", artifact["id"]) (status_code, return_data) = \ Utils.make_rest_request("delete", url, data=artifact) if status_code == 200: logger.info( "Marathon app %s sucessfully deleted.", artifact["id"]) else: msg = "Error deleting app: %s, Marathon API response %s - %s" % ( artifact["id"], status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def scale(self, url, replicas): """ Scale ReplicationControllers or DeploymentConfig Args: url (str): full url for artifact replicas (int): number of replicas scale to """ patch = [{ "op": "replace", "path": "/spec/replicas", "value": replicas }] (status_code, return_data) = \ Utils.make_rest_request("patch", url, data=patch, verify=self._requests_tls_verify()) if status_code == 200: logger.info("Successfully scaled to %s replicas", replicas) else: msg = "%s %s" % (status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def process_template(self, url, template): (status_code, return_data) = \ Utils.make_rest_request("post", url, verify=self._requests_tls_verify(), data=template) if status_code == 201: logger.info("template processed %s", template['metadata']['name']) logger.debug("processed template %s", return_data) return return_data['objects'] else: msg = "%s %s" % (status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def deploy(self, url, artifact): (status_code, return_data) = \ Utils.make_rest_request("post", url, verify=self._requests_tls_verify(), data=artifact) if status_code == 201: logger.info("Object %s successfully deployed.", artifact['metadata']['name']) else: msg = "%s %s" % (status_code, return_data) logger.error(msg) # TODO: remove running components (issue: #428) raise ProviderFailedException(msg)
def get_oapi_resources(self): """ Get Openshift API resources """ # get list of supported resources for each api (status_code, return_data) = \ Utils.make_rest_request("get", self.openshift_api, verify=self._requests_tls_verify()) if status_code == 200: oapi_resources = return_data["resources"] else: raise ProviderFailedException("Cannot get OpenShift resource list") # convert resources list of dicts to list of names oapi_resources = [res['name'] for res in oapi_resources] logger.debug("Openshift resources %s", oapi_resources) return oapi_resources
def delete(self, url): """ Delete object on given url Args: url (str): full url for artifact Raises: ProviderFailedException: error when calling remote api """ (status_code, return_data) = \ Utils.make_rest_request("delete", url, verify=self._requests_tls_verify()) if status_code == 200: logger.info("Successfully deleted.") else: msg = "%s %s" % (status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def get_kapi_resources(self): """ Get kubernetes API resources """ # get list of supported resources for each api (status_code, return_data) = \ Utils.make_rest_request("get", self.kubernetes_api, verify=self._requests_tls_verify()) if status_code == 200: kapi_resources = return_data["resources"] else: raise ProviderFailedException("Cannot get Kubernetes resource list") # convert resources list of dicts to list of names kapi_resources = [res['name'] for res in kapi_resources] logger.debug("Kubernetes resources %s", kapi_resources) return kapi_resources
def run(self): """ Deploys the app by given resource manifests. """ for artifact in self.marathon_artifacts: url = urlparse.urljoin(self.marathon_api, "apps/") if self.dryrun: logger.info("DRY-RUN: %s", url) continue logger.debug("Deploying appid: %s", artifact["id"]) (status_code, return_data) = \ Utils.make_rest_request("post", url, data=artifact) if status_code == 201: logger.info("Marathon app %s sucessfully deployed.", artifact["id"]) else: msg = "Error deploying app: %s, Marathon API response %s - %s" % ( artifact["id"], status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def scale(self, url, replicas): """ Scale ReplicationControllers or DeploymentConfig Args: url (str): full url for artifact replicas (int): number of replicas scale to """ patch = [{"op": "replace", "path": "/spec/replicas", "value": replicas}] (status_code, return_data) = \ Utils.make_rest_request("patch", url, data=patch, verify=self._requests_tls_verify()) if status_code == 200: logger.info("Successfully scaled to %s replicas", replicas) else: msg = "%s %s" % (status_code, return_data) logger.error(msg) raise ProviderFailedException(msg)
def stop(self): """ Undeploy application. Cascade the deletion of the resources managed other resource (e.g. ReplicationControllers created by a DeploymentConfig and Pods created by a ReplicationController). When using command line client this is done automatically by `oc` command. When using API calls we have to cascade deletion manually. """ logger.debug("Starting undeploy") delete_artifacts = [] for kind, objects in self.openshift_artifacts.iteritems(): # Add deployment configs to beginning of the list so they are deleted first. # Do deployment config first because if you do replication controller # before deployment config then the deployment config will re-spawn # the replication controller before the deployment config is deleted. if kind == "deploymentconfig": delete_artifacts = objects + delete_artifacts else: delete_artifacts = delete_artifacts + objects for artifact in delete_artifacts: kind = artifact["kind"].lower() namespace = self._get_namespace(artifact) # Get name from metadata so we know which object to delete. if "metadata" in artifact and \ "name" in artifact["metadata"]: name = artifact["metadata"]["name"] else: raise ProviderFailedException("Cannot undeploy. There is no" " name in artifacts metadata " "artifact=%s" % artifact) logger.info("Undeploying artifact name=%s kind=%s" % (name, kind)) # If this is a deployment config we need to delete all # replication controllers that were created by this. # Find the replication controller that was created by this deployment # config by querying for all replication controllers and filtering based # on automatically created label openshift.io/deployment-config.name if kind.lower() == "deploymentconfig": params = {"labelSelector": "openshift.io/deployment-config.name=%s" % name} url = self._get_url(namespace, "replicationcontroller", params=params) (status_code, return_data) = \ Utils.make_rest_request("get", url, verify=self.oc._requests_tls_verify()) if status_code != 200: raise ProviderFailedException("Cannot get Replication" "Controllers for Deployment" "Config %s (status code %s)" % (name, status_code)) # kind of returned data is ReplicationControllerList # https://docs.openshift.com/enterprise/3.1/rest_api/kubernetes_v1.html#v1-replicationcontrollerlist # we need modify items to get valid ReplicationController items = return_data["items"] for item in items: item["kind"] = "ReplicationController" item["apiVersion"] = return_data["apiVersion"] # add items to list of artifact to be deleted delete_artifacts.extend(items) url = self._get_url(namespace, kind, name) # Scale down replication controller to 0 replicas before deleting. # This should take care of all pods created by this replication # controller and we can safely delete it. if kind.lower() == "replicationcontroller": if self.dryrun: logger.info("DRY-RUN: SCALE %s down to 0", url) else: self.oc.scale(url, 0) if self.dryrun: logger.info("DRY-RUN: DELETE %s", url) else: self.oc.delete(url)
def undeploy(self): """ Undeploy application. Cascade the deletion of the resources managed other resource (e.g. ReplicationControllers created by a DeploymentConfig and Pods created by a ReplicationController). When using command line client this is done automatically by `oc` command. When using API calls we have to cascade deletion manually. """ logger.debug("Starting undeploy") delete_artifacts = [] for kind, objects in self.openshift_artifacts.iteritems(): delete_artifacts.extend(objects) for artifact in delete_artifacts: kind = artifact["kind"].lower() namespace = self._get_namespace(artifact) # get name from metadata so we know which object to delete if "metadata" in artifact and \ "name" in artifact["metadata"]: name = artifact["metadata"]["name"] else: raise ProviderFailedException("Cannot undeploy. There is no" " name in artifacts metadata " "artifact=%s" % artifact) logger.info("Undeploying artifact name=%s kind=%s" % (name, kind)) # If this is a DeploymentConfig we need to delete all # ReplicationControllers that were created by this DC. Find the RC # that belong to this DC by querying for all RC and filtering based # on automatically created label openshift.io/deployment-config.name if kind.lower() == "deploymentconfig": params = {"labelSelector": "openshift.io/deployment-config.name=%s" % name} url = self._get_url(namespace, "replicationcontroller", params=params) (status_code, return_data) = \ Utils.make_rest_request("get", url, verify=self.oc._requests_tls_verify()) if status_code != 200: raise ProviderFailedException("Cannot get Replication" "Controllers for Deployment" "Config %s (status code %s)" % (name, status_code)) # kind of returned data is ReplicationControllerList # https://docs.openshift.com/enterprise/3.1/rest_api/kubernetes_v1.html#v1-replicationcontrollerlist # we need modify items to get valid ReplicationController items = return_data["items"] for item in items: item["kind"] = "ReplicationController" item["apiVersion"] = return_data["apiVersion"] # add items to list of artifact to be deleted delete_artifacts.extend(items) # If this is a ReplicationController we need to delete all # Pods that were created by this RC. Find the pods that # belong to this RC by querying for all pods and filtering # based on the selector used in the RC. if kind.lower() == "replicationcontroller": selector = ",".join(["%s=%s" % (k, v) for k, v in artifact["spec"]["selector"].iteritems()]) logger.debug("Using labelSelector: %s" % selector) params = {"labelSelector": selector} url = self._get_url(namespace, "pod", params=params) (status_code, return_data) = \ Utils.make_rest_request("get", url, verify=self.oc._requests_tls_verify()) if status_code != 200: raise ProviderFailedException("Cannot get Pods for " "ReplicationController %s" " (status code %s)" % (name, status_code)) # kind of returned data is ReplicationControllerList # https://docs.openshift.com/enterprise/3.1/rest_api/kubernetes_v1.html#v1-podlist # we need to modify items to get valid Pod items = return_data["items"] for item in items: item["kind"] = "Pod" item["apiVersion"] = return_data["apiVersion"] # add items to list of artifact to be deleted delete_artifacts.extend(items) url = self._get_url(namespace, kind, name) if self.dryrun: logger.info("DRY-RUN: DELETE %s", url) else: self.oc.delete(url)