def create(self, request, *args, **kwargs): """ Create project by only admin users. """ self.check_admin_permission() project = Project.objects.filter(name=request.data.get('name', None)) if project: raise ValidationError(detail="Already has an project called {}." .format(request.data['name'])) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) response = Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) # Create the namespace try: kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) kubeclient.create_namespace(serializer.data['name']) except Exception as e: logger.error(e) logger.info("User {} create a new project {}.".format( request.user.username, serializer.data['name'])) return response
def get_optimal_external_ip(namespace, app_name): """ Return the optimal external ip from all host ips of the application. """ kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) label = "app=" + app_name hosts = kubeclient.list_host_ips(namespace=namespace, label=label) # logger.debug(hosts) index = random.randint(0, len(hosts) - 1) return hosts[index]
def pod_lists(self, request, *args, **kwargs): """ Return the pods list of the application with json. """ application = self.get_object() if not application: raise ValidationError(detail="The application doesn't exist.") kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) pods = kubeclient.list_pods(namespace=application.image.project.name, label="app={}".format(get_application_instance_name(application))) logger.debug(pods) return Response(pods, status=status.HTTP_200_OK)
def __init__(self, application, image_name, tcp_ports=None, udp_ports=None, commands=None, args=None, envs=None, is_public=False, volumes=None, min_replicas=None, max_replicas=None, cpu_target=None): self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.application = application self.namespace = self.application.image.project.name self.application_name = get_application_instance_name(self.application) self.image_name = image_name self.tcp_ports = tcp_ports self.udp_ports = udp_ports self.commands = commands self.args = args self.envs = envs self.is_public = is_public self.volumes = volumes # Compute the resource limit of the application resource_limit = self.application.resource_limit self.cpu = str(resource_limit.cpu) + resource_limit.cpu_unit self.memory = str(resource_limit.memory) + resource_limit.memory_unit # autoscaler if self.application.is_autoscaler: self.min_replicas = int(min_replicas) self.max_replicas = int(max_replicas) self.cpu_target = int(cpu_target) logger.debug(str(self.min_replicas) + " " + str(self.max_replicas) + " " + str(self.cpu_target))
class AutoScalerDestroyer(object): """ AutoScalerDestroyer is to destroy autoscaler instance when deleting application. """ def __init__(self, application): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_V1BETA1_API_PATH)) def delete_autoscaler(self): """ Destroy autoscaler for application instance by multiple threading. """ deleting_thread = Thread(target=self._delete_autoscaler_instance) deleting_thread.start() def _delete_autoscaler_instance(self): scalers = AutoScaler.objects.filter(app=self.application) for scaler in scalers: scaler.delete() ok = self.kubeclient.delete_autoscaler(namespace=self.namespace, name=self.application_name) if not ok: logger.error("Delete autoscaler {} failed.".format( self.application_name)) else: logger.debug("Delete autoscaler {} successfully.".format( self.application_name))
def __init__(self, application): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_V1BETA1_API_PATH))
def destroy(self, request, *args, **kwargs): """ Destroy an Project instance. """ self.check_admin_permission() project = self.get_object() # Delete the namespace try: kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) kubeclient.delete_namespace(project.name) except Exception as e: logger.error(e) logger.info("User {} delete the project {}.".format( request.user.username, project.name)) return super(ProjectViewSet, self).destroy(request, *args, **kwargs)
def __init__(self, application, min_replicas=-1, max_replicas=-1, cpu_target=-1): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.min_replicas = min_replicas self.max_replicas = max_replicas self.cpu_target = cpu_target self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_V1BETA1_API_PATH))
def __init__(self, application, image_name, tcp_ports=None, udp_ports=None, commands=None, args=None, envs=None, is_public=False, volumes=None, min_replicas=None, max_replicas=None, cpu_target=None): self.kubeclient = KubeClient("http://{}:{}{}".format( settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.application = application self.namespace = self.application.image.project.name self.application_name = get_application_instance_name(self.application) self.image_name = image_name self.tcp_ports = tcp_ports self.udp_ports = udp_ports self.commands = commands self.args = args self.envs = envs self.is_public = is_public self.volumes = volumes # Compute the resource limit of the application resource_limit = self.application.resource_limit self.cpu = str(resource_limit.cpu) + resource_limit.cpu_unit self.memory = str(resource_limit.memory) + resource_limit.memory_unit # autoscaler if self.application.is_autoscaler: self.min_replicas = int(min_replicas) self.max_replicas = int(max_replicas) self.cpu_target = int(cpu_target) logger.debug( str(self.min_replicas) + " " + str(self.max_replicas) + " " + str(self.cpu_target))
def __init__(self, volume): self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.volume = volume self.namespace = self.volume.project.name self.project_name = self.volume.project.name self.volume_name = self.volume.name self.capacity = str(self.volume.capacity) + self.volume.capacity_unit self.nfs_path = get_volume_nfs_dir(settings.NFS_BASE_DIR, self.namespace, self.volume.name) self.nfs_server = settings.NFS_IP
def list_pods(self, request, *args, **kwargs): """ AdminUser search pods for application id. """ user = self.request.user if not user.is_staff: raise PermissionDenied() app_id = request.GET.get('app', 0) try: application = Application.objects.get(id=app_id) except Exception: return Response(status=status.HTTP_200_OK) kubeclient = KubeClient("http://{}:{}{}".format( settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) pods = kubeclient.list_pods( namespace=application.image.project.name, label="app={}".format(get_application_instance_name(application))) logger.debug(pods) return Response(pods, status=status.HTTP_200_OK)
def list_pods(self, request, *args, **kwargs): """ AdminUser search pods for application id. """ user = self.request.user if not user.is_staff: raise PermissionDenied() app_id = request.GET.get('app', 0) try: application = Application.objects.get(id=app_id) except Exception: return Response(status=status.HTTP_200_OK) kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) pods = kubeclient.list_pods( namespace=application.image.project.name, label="app={}".format(get_application_instance_name(application))) logger.debug(pods) return Response(pods, status=status.HTTP_200_OK)
class AutoScalerBuilder(object): """ AutoScalerBuilder is a builder to create an autoscaler for application. You should offer many necessary arguments. Parameters: min_replicas, max_replicas, cpu_target: integer parameters, -1 represents infinite big value. """ def __init__(self, application, min_replicas=-1, max_replicas=-1, cpu_target=-1): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.min_replicas = min_replicas self.max_replicas = max_replicas self.cpu_target = cpu_target self.kubeclient = KubeClient("http://{}:{}{}".format( settings.MASTER_IP, settings.K8S_PORT, settings.K8S_V1BETA1_API_PATH)) def create_autoscaler(self): """ Create autoscaler instance for application by multiple threading. """ creating_thread = Thread(target=self._create_autoscaler_instance) creating_thread.start() def _create_autoscaler_instance(self): ok = self.kubeclient.create_autoscaler(namespace=self.namespace, name=self.application_name, minReplicas=self.min_replicas, maxReplicas=self.max_replicas, cpu_target=self.cpu_target) if not ok: logger.error("Create autoscaler {} failed.".format( self.application_name)) return None logger.debug("Create autoscaler {} successfully.".format( self.application_name)) scaler = AutoScaler(app=self.application, min_replicas=self.min_replicas, max_replicas=self.max_replicas, cpu_target=self.cpu_target) scaler.save()
def logs_pod(self, request, *args, **kwargs): """ Return the tail n lines logs of pod. """ user = request.user assert 'pid' in self.kwargs pid = self.kwargs['pid'] project = Project.objects.get(id=pid) if not check_member_in_project(project, user): raise PermissionDenied(detail="User {} is not in project {}." .format(user.username, project.name)) assert 'pod' in self.kwargs pod = self.kwargs['pod'] tailLine = int(request.query_params['tail']) kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) logs = kubeclient.get_logs_of_pod(project.name, pod, tailLine) # print(logs) return Response(data=logs, status=status.HTTP_200_OK)
class AutoScalerBuilder(object): """ AutoScalerBuilder is a builder to create an autoscaler for application. You should offer many necessary arguments. Parameters: min_replicas, max_replicas, cpu_target: integer parameters, -1 represents infinite big value. """ def __init__(self, application, min_replicas=-1, max_replicas=-1, cpu_target=-1): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.min_replicas = min_replicas self.max_replicas = max_replicas self.cpu_target = cpu_target self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_V1BETA1_API_PATH)) def create_autoscaler(self): """ Create autoscaler instance for application by multiple threading. """ creating_thread = Thread(target=self._create_autoscaler_instance) creating_thread.start() def _create_autoscaler_instance(self): ok = self.kubeclient.create_autoscaler( namespace=self.namespace, name=self.application_name, minReplicas=self.min_replicas, maxReplicas=self.max_replicas, cpu_target=self.cpu_target) if not ok: logger.error("Create autoscaler {} failed.".format( self.application_name)) return None logger.debug("Create autoscaler {} successfully.".format( self.application_name)) scaler = AutoScaler(app=self.application, min_replicas=self.min_replicas, max_replicas=self.max_replicas, cpu_target=self.cpu_target) scaler.save()
def test_add_slash(self): url = "http://192.168.0.10:8080" self.assertEqual(KubeClient.add_slash(url), "http://192.168.0.10:8080/")
def test_delete_autoscaler(self): beta_client = KubeClient( "http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.delete_autoscaler('user', 'project0-nginx-test') print(res)
def test_create_instance(self): url = "http://192.168.0.10:8080" client = KubeClient(url) self.assertEqual(client.base_url, "http://192.168.0.10:8080/")
class KubeClientTestCase(unittest.TestCase): def setUp(self): self.client = KubeClient("http://192.168.0.10:8080/api/v1/") def tearDown(self): self.client = None def test_add_slash(self): url = "http://192.168.0.10:8080" self.assertEqual(KubeClient.add_slash(url), "http://192.168.0.10:8080/") def test_create_instance(self): url = "http://192.168.0.10:8080" client = KubeClient(url) self.assertEqual(client.base_url, "http://192.168.0.10:8080/") def test_send_request(self): res = self.client.send_request("get", "namespaces", labels={ 'a': 1, 'name': 'wangtao' }) self.assertEqual(isinstance(res, dict), True) def test_list_namespaces(self): namespaces = self.client.list_namespces() print(namespaces) self.assertEqual(True, True) def test_list_nodes(self): nodes = self.client.list_nodes() print(nodes) self.assertEqual(True, True) def test_create_namespace(self): self.client.create_namespace('user') def test_delete_namespace(self): self.client.delete_namespace('abcd') def test_list_controllers(self): controllers = self.client.list_controllers('user') print(controllers) def test_create_controller_1(self): image_name = '192.168.0.15:5000/user/nginx:1.9.9' res = self.client.create_controller('user', 'test-nginx', image_name, replicas=2, tcp_ports={"http": 80}) print(res) def test_create_controller_2(self): image_name = '192.168.0.15:5000/admin/ubuntu:14.04' self.client.create_controller('test-space', 'test-nginx', image_name, replicas=1, commands=['sleep', '3600'], envs={"MYSQL": "192.168.0.100"}) def test_create_controller_3(self): image_name = '192.168.0.15:5000/admin/nginx:1.9.9' self.client.create_controller('test-space', 'test-nginx', image_name, replicas=1, tcp_ports={ "http": 80, "https": 443 }) def test_create_controller_volume(self): image_name = '192.168.0.15:5000/user/nginx:1.9.9' self.client.create_controller( 'user', 'test-nginx', image_name, cpu="100m", memory="64Mi", replicas=1, tcp_ports={"http": 80}, volumes={"project0-volume0": "/var/www/html"}) def test_delete_controller(self): self.client.delete_controller('test-space', 'test-nginx') def test_list_services(self): services = self.client.list_services('test-space') print(services) def test_create_service_internal(self): res = self.client.create_service('user', 'test-nginx', tcp_ports={"http": 80}, is_public=False) print(res) def test_create_service_external(self): res = self.client.create_service('test-space', 'test-nginx', tcp_ports={"http": 80}, is_public=True) print(res) def test_create_service_session(self): self.client.create_service('test-space', 'nginx', tcp_ports={"http": 80}, is_public=True, session_affinity=True) def test_delete_service(self): self.client.delete_service('test-space', 'nginx') def test_get_service_details(self): res = self.client.get_service_details('test-space', 'test-nginx') print(res) def test_create_persistentvolume(self): res = self.client.create_persistentvolume( 'default', 'project0-volume0', '10Mi', '/hummer/user/project0/volume0', '192.168.0.15') print(res) def test_delete_persistentvolume(self): res = self.client.delete_persistentvolume('default', 'project0-volume0') print(res) def test_create_persistentvolumeclaim(self): res = self.client.create_persistentvolumeclaim('default', 'project0-volume0', '10Mi') print(res) def test_delete_persistentvolumeclaim(self): res = self.client.delete_persistentvolumeclaim('default', 'project0-volume0') print(res) def test_list_pods(self): res = self.client.list_pods('user', label="app=project0-nginx-test") print(res) def test_get_logs_of_pod(self): res = self.client.get_logs_of_pod('user', 'project0-nginx-test-3uhej', 20) lines = res.split('\n') print(lines) def test_create_autoscaler(self): beta_client = KubeClient( "http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.create_autoscaler('user', 'project0-nginx-test', 1, 5, 50) print(res) def test_delete_autoscaler(self): beta_client = KubeClient( "http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.delete_autoscaler('user', 'project0-nginx-test') print(res) def test_list_host_ips(self): hosts = self.client.list_host_ips('user', "app=project0-2048") print(hosts)
class ApplicationDestroyer(object): """ ApplicationDestroyer is to destroy application instance, including controller and service. """ application = None def __init__(self, application): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.service_name = self.application_name self.controller_name = self.application_name self.kubeclient = KubeClient("http://{}:{}{}".format( settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) def destroy_application_instance(self): """ Destroy application instance by multiple threading. """ deleting_thread = Thread(target=self._destroy_application_instance) deleting_thread.start() def _destroy_application_instance(self): self._update_application_status(status='deleting') if not self._destroy_service_instance(): logger.debug("Delete service {} failed.".format(self.service_name)) if not self._destroy_controller_instance(): logger.debug("Delete controller {} failed.".format( self.controller_name)) if not self._destroy_pods_instance(): logger.debug("Delete pods with label 'app={}' failed.".format( self.controller_name)) self._update_application_status(status='deleted') self._umount_volume() # delete autoscaler if self.application.is_autoscaler: autoscaler_destroyer = AutoScalerDestroyer(self.application) autoscaler_destroyer.delete_autoscaler() self._delete_application_metadata() self._delete_port_metadata() self._delete_environments() def _destroy_service_instance(self): return self.kubeclient.delete_service(namespace=self.namespace, name=self.service_name) def _destroy_controller_instance(self): return self.kubeclient.delete_controller(namespace=self.namespace, name=self.controller_name) def _destroy_pods_instance(self): pods = self.kubeclient.list_pods(namespace=self.namespace, label="app={}".format( self.controller_name)) logger.debug(pods) res = True for pod in pods: flag = self.kubeclient.delete_pod(namespace=self.namespace, name=pod) if not flag: res = False return res def _update_application_status(self, status): self.application.status = status self.application.save() def _delete_application_metadata(self): logger.debug("delete application medatada.") self.application.delete() def _delete_port_metadata(self): logger.debug("delete port metadata.") ports = Port.objects.filter(app=self.application) for port in ports: logger.debug("delete port {} metadata.".format(port.name)) port.delete() def _delete_environments(self): envs = Environment.objects.filter(app=self.application) for env in envs: env.delete() def _umount_volume(self): """ Umount volumes which mounted on application. """ volumes = Volume.objects.filter(app=self.application) for volume in volumes: logger.debug("umount volume {}-{} from application {}.".format( volume.project.name, volume.name, self.application_name)) volume.app = None volume.mount_path = None volume.save()
def setUp(self): self.client = KubeClient("http://192.168.0.10:8080/api/v1/")
class KubeClientTestCase(unittest.TestCase): def setUp(self): self.client = KubeClient("http://192.168.0.10:8080/api/v1/") def tearDown(self): self.client = None def test_add_slash(self): url = "http://192.168.0.10:8080" self.assertEqual(KubeClient.add_slash(url), "http://192.168.0.10:8080/") def test_create_instance(self): url = "http://192.168.0.10:8080" client = KubeClient(url) self.assertEqual(client.base_url, "http://192.168.0.10:8080/") def test_send_request(self): res = self.client.send_request("get", "namespaces", labels={'a': 1, 'name': 'wangtao'}) self.assertEqual(isinstance(res, dict), True) def test_list_namespaces(self): namespaces = self.client.list_namespces() print(namespaces) self.assertEqual(True, True) def test_list_nodes(self): nodes = self.client.list_nodes() print(nodes) self.assertEqual(True, True) def test_create_namespace(self): self.client.create_namespace('user') def test_delete_namespace(self): self.client.delete_namespace('abcd') def test_list_controllers(self): controllers = self.client.list_controllers('user') print(controllers) def test_create_controller_1(self): image_name = '192.168.0.15:5000/user/nginx:1.9.9' res = self.client.create_controller('user', 'test-nginx', image_name, replicas=2, tcp_ports={"http": 80}) print(res) def test_create_controller_2(self): image_name = '192.168.0.15:5000/admin/ubuntu:14.04' self.client.create_controller('test-space', 'test-nginx', image_name, replicas=1, commands=['sleep', '3600'], envs={"MYSQL": "192.168.0.100"} ) def test_create_controller_3(self): image_name = '192.168.0.15:5000/admin/nginx:1.9.9' self.client.create_controller('test-space', 'test-nginx', image_name, replicas=1, tcp_ports={"http": 80, "https": 443}) def test_create_controller_volume(self): image_name = '192.168.0.15:5000/user/nginx:1.9.9' self.client.create_controller('user', 'test-nginx', image_name, cpu="100m", memory="64Mi", replicas=1, tcp_ports={"http": 80}, volumes={"project0-volume0": "/var/www/html"}) def test_delete_controller(self): self.client.delete_controller('test-space', 'test-nginx') def test_list_services(self): services = self.client.list_services('test-space') print(services) def test_create_service_internal(self): res = self.client.create_service('user', 'test-nginx', tcp_ports={"http": 80}, is_public=False ) print(res) def test_create_service_external(self): res = self.client.create_service('test-space', 'test-nginx', tcp_ports={"http": 80}, is_public=True ) print(res) def test_create_service_session(self): self.client.create_service('test-space', 'nginx', tcp_ports={"http": 80}, is_public=True, session_affinity=True ) def test_delete_service(self): self.client.delete_service('test-space', 'nginx') def test_get_service_details(self): res = self.client.get_service_details('test-space', 'test-nginx') print(res) def test_create_persistentvolume(self): res = self.client.create_persistentvolume('default', 'project0-volume0', '10Mi', '/hummer/user/project0/volume0', '192.168.0.15') print(res) def test_delete_persistentvolume(self): res = self.client.delete_persistentvolume('default', 'project0-volume0') print(res) def test_create_persistentvolumeclaim(self): res = self.client.create_persistentvolumeclaim('default', 'project0-volume0', '10Mi') print(res) def test_delete_persistentvolumeclaim(self): res = self.client.delete_persistentvolumeclaim('default', 'project0-volume0') print(res) def test_list_pods(self): res = self.client.list_pods('user', label="app=project0-nginx-test") print(res) def test_get_logs_of_pod(self): res = self.client.get_logs_of_pod('user', 'project0-nginx-test-3uhej', 20) lines = res.split('\n') print(lines) def test_create_autoscaler(self): beta_client = KubeClient("http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.create_autoscaler('user', 'project0-nginx-test', 1, 5, 50) print(res) def test_delete_autoscaler(self): beta_client = KubeClient("http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.delete_autoscaler('user', 'project0-nginx-test') print(res) def test_list_host_ips(self): hosts = self.client.list_host_ips('user', "app=project0-2048") print(hosts)
class VolumeDestroyer(object): """ VolumeDestroyer is to destroy volume instance, including volume direction, persistentvolume and persistentvolumeclaim. """ volume = None def __init__(self, volume): self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.volume = volume self.namespace = self.volume.project.name self.project_name = self.volume.project.name self.volume_name = self.volume.name self.capacity = str(self.volume.capacity) + self.volume.capacity_unit self.nfs_path = get_volume_nfs_dir(settings.NFS_BASE_DIR, self.namespace, self.volume.name) self.nfs_server = settings.NFS_IP def destroy_volume(self): """ Destroy volume instance by multiple threading. """ deleting_thread = Thread(target=self._destroy_volume_instance) deleting_thread.start() def _destroy_volume_instance(self): logger.info('User {} delete volume {} in project {}.'.format( self.volume.user.username, self.volume.name, self.project_name)) self._update_volume_status(status='deleting') if not self._remove_volume_dir_on_nfs(): logger.debug("remove direction {} on nfs server failed.".format( self.nfs_path)) else: logger.info("remove direction {} on nfs server successfully." .format(self.nfs_path)) if not self._delete_persistentvolumeclaim(): logger.debug("delete persistentvolumeclaim {} failed.".format( self.volume_name)) else: logger.debug("delete persistentvolumeclaim {} successfully." .format(self.volume_name)) if not self._delete_persistentvolume(): logger.debug("delete persistentvolume {}-{} failed.".format( self.namespace, self.volume_name)) else: logger.debug("delete persistentvolume {}-{} successfully.".format( self.namespace, self.volume_name)) # self._update_volume_status(status='deleted') self._delete_volume_metadata() def _remove_volume_dir_on_nfs(self): """ Remove direction on nfs server. """ client = NFSLocalClient() client.removedir(self.nfs_path) return True def _delete_persistentvolumeclaim(self): return self.kubeclient.delete_persistentvolumeclaim( namespace=self.namespace, name=self.volume_name) def _delete_persistentvolume(self): return self.kubeclient.delete_persistentvolume( namespace=self.namespace, name=self.volume_name) def _update_volume_status(self, status): self.volume.status = status self.volume.save() def _delete_volume_metadata(self): logger.debug("delete volume {} metadata.".format(self.volume_name)) self.volume.delete()
class ApplicationBuilder(object): """ ApplicationBuilder is a builder to create an appliction from an image. You should offer many necessary arguments. Parameters: image_name: the image name for the container. tcp_ports: a dict, the tcp ports of the containers. For example: { "http": 80, "https": 443} udp_ports: a dict, the udp ports of the containers. commands: the commands which the container runs when start. envs: a dict for example: {"MYSQL_HOST": "localhost", "PORT": "3306"} volumes: a dict, for example: [{"volume": id, "mount_path": path}] """ namespace = None application = None image_name = None tcp_ports = None udp_ports = None commands = None args = None envs = None is_public = False volumes = None def __init__(self, application, image_name, tcp_ports=None, udp_ports=None, commands=None, args=None, envs=None, is_public=False, volumes=None, min_replicas=None, max_replicas=None, cpu_target=None): self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.application = application self.namespace = self.application.image.project.name self.application_name = get_application_instance_name(self.application) self.image_name = image_name self.tcp_ports = tcp_ports self.udp_ports = udp_ports self.commands = commands self.args = args self.envs = envs self.is_public = is_public self.volumes = volumes # Compute the resource limit of the application resource_limit = self.application.resource_limit self.cpu = str(resource_limit.cpu) + resource_limit.cpu_unit self.memory = str(resource_limit.memory) + resource_limit.memory_unit # autoscaler if self.application.is_autoscaler: self.min_replicas = int(min_replicas) self.max_replicas = int(max_replicas) self.cpu_target = int(cpu_target) logger.debug(str(self.min_replicas) + " " + str(self.max_replicas) + " " + str(self.cpu_target)) def create_application(self): """ Create application by multiple threading. """ creating_thread = Thread(target=self._create_application) creating_thread.start() def _create_application(self): """ First create a replicationcontroller, then create a service, update database at last. """ logger.info('Create an application {} in namespace {} by image {}.' .format(self.application_name, self.namespace, self.image_name)) if not self._create_controller(): logger.debug('Create controller {} failed.'.format( self.application_name)) logger.info('Create an application {} in namespace {} failed.' .format(self.application_name, self.namespace, self.image_name)) self._update_application_metadata(status='error') return None if self.tcp_ports or self.udp_ports: if not self._create_service(): logger.debug('Create service {} failed.'.format( self.application_name)) logger.info('Create an application {} in namespace {} failed.' .format(self.application_name, self.namespace, self.image_name)) self._update_application_metadata(status='error') return None internal_ip, ports = self._get_service_ip_and_ports() else: internal_ip = None ports = None # update metadata if self.is_public: external_ip = get_optimal_external_ip(namespace=self.namespace, app_name=self.application_name) self._update_application_metadata(status='active', internal_ip=internal_ip, external_ip=external_ip ) else: self._update_application_metadata(status='active', internal_ip=internal_ip ) # mount volume self._mount_volume_onto_application() # create port metadata self._create_ports_metadata(ports) # create environment metadata self._create_environments_metadata() # create autoscaler if self.application.is_autoscaler: scaler_builder = AutoScalerBuilder( application=self.application, min_replicas=self.min_replicas, max_replicas=self.max_replicas, cpu_target=self.cpu_target ) scaler_builder.create_autoscaler() def _create_controller(self): """ Create a replicationcontroller by provided image. """ return self.kubeclient.create_controller(namespace=self.namespace, name=self.application_name, image_name=self.image_name, cpu=self.cpu, memory=self.memory, replicas=self.application.replicas, tcp_ports=self.tcp_ports, udp_ports=self.udp_ports, commands=self.commands, args=self.args, envs=self.envs, volumes=self._get_volume_names_and_path() ) def _create_service(self): """ Create a service on the replicationcontroller. """ return self.kubeclient.create_service(namespace=self.namespace, name=self.application_name, tcp_ports=self.tcp_ports, udp_ports=self.udp_ports, is_public=self.is_public, session_affinity=self.application.session_affinity ) def _get_service_ip_and_ports(self): """ Get internal_ip and ports of the service. """ response = self.kubeclient.get_service_details(self.namespace, self.application_name) return (response['spec']['clusterIP'], response['spec']['ports']) def _update_application_metadata(self, status=None, internal_ip=None, external_ip=None): """ Update the application metadata. """ if status: self.application.status = status if internal_ip: self.application.internal_ip = internal_ip if external_ip: self.application.external_ip = external_ip self.application.save() def _create_ports_metadata(self, ports): """ Create ports metadata for application. """ if not ports: return None for port_dict in ports: port = Port(app=self.application, name=port_dict['name'], protocol=port_dict['protocol'], external_port=port_dict.get('nodePort', None), internal_port=port_dict['port'] ) port.save() def _create_environments_metadata(self): """ Create environment metadata for application. """ if not self.envs: return None for name, value in self.envs.items(): env = Environment(app=self.application, name=name, value=value) env.save() def _mount_volume_onto_application(self): """ Edit the metadata, Mount volumes onto this application. """ if not self.volumes: return None for volume_item in self.volumes: volume = Volume.objects.get(id=volume_item['volume']) logger.debug("mount volume {} onto application {}.".format( volume.name, self.application_name)) volume.app = self.application volume.mount_path = volume_item['mount_path'] volume.save() def _get_volume_names_and_path(self): """ Return the volume names from volume ids. The true volume instance name is "project_name-volume_name". """ if not self.volumes: return None volume_name_path = {} for volume_item in self.volumes: volume = Volume.objects.get(id=int(volume_item['volume'])) volume_name = "{}-{}".format(self.namespace, volume.name) volume_name_path[volume_name] = volume_item['mount_path'] logger.debug(volume_name_path) return volume_name_path
class VolumeBuilder(object): """ VolumeBuilder is a builder to create an volume for persistent data storagy. """ volume = None def __init__(self, volume): self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.volume = volume self.namespace = self.volume.project.name self.project_name = self.volume.project.name self.volume_name = self.volume.name self.capacity = str(self.volume.capacity) + self.volume.capacity_unit self.nfs_path = get_volume_nfs_dir(settings.NFS_BASE_DIR, self.namespace, self.volume.name) self.nfs_server = settings.NFS_IP def create_volume(self): """ Create volume by multiple threading. """ creating_thread = Thread(target=self._create_volume) creating_thread.start() def _create_volume(self): """ First create a persistentvolume, then create a persistentvolumeclaim. """ logger.info('User {} create a volume {} in project {}.'.format( self.volume.user.username, self.volume.name, self.project_name)) # create volume dir on nfs server if self._create_volume_dir_on_nfs(): logger.info("Create dir {} on nfs server {} successfully.".format( self.nfs_path, self.nfs_server)) else: logger.info("Create dir {} on nfs server {} failed.".format( self.nfs_path, self.nfs_server)) self._update_volume_status(status='error') return None # create persistentvolume if self._create_persistentvolume(): logger.info("Create persistentvolume {}-{} successfully.".format( self.namespace, self.volume_name)) else: logger.info("Create persistentvolume {}-{} failed.".format( self.namespace, self.volume_name)) self._update_volume_status(status='error') return None # create persistentvolumeclaim if self._create_persistentvolumeclaim(): logger.info("Create persistentvolumeclaim {} successfully.".format( self.volume_name)) else: logger.info("Create persistentvolumeclaim {} failed.".format( self.volume_name)) self._update_volume_status(status='error') return None self._update_volume_status(status='active') def _create_volume_dir_on_nfs(self): """ Create direction on nfs server to store volume data. """ client = NFSLocalClient() client.removedir(self.nfs_path) client.makedir(self.nfs_path) return True def _create_persistentvolume(self): return self.kubeclient.create_persistentvolume( namespace=self.namespace, name=self.volume_name, capacity=self.capacity, nfs_path=self.nfs_path, nfs_server=self.nfs_server ) def _create_persistentvolumeclaim(self): return self.kubeclient.create_persistentvolumeclaim( namespace=self.namespace, name=self.volume_name, capacity=self.capacity ) def _update_volume_status(self, status): self.volume.status = status self.volume.save()
class ApplicationDestroyer(object): """ ApplicationDestroyer is to destroy application instance, including controller and service. """ application = None def __init__(self, application): self.application = application self.application_name = get_application_instance_name(self.application) self.namespace = self.application.image.project.name self.service_name = self.application_name self.controller_name = self.application_name self.kubeclient = KubeClient("http://{}:{}{}".format(settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) def destroy_application_instance(self): """ Destroy application instance by multiple threading. """ deleting_thread = Thread(target=self._destroy_application_instance) deleting_thread.start() def _destroy_application_instance(self): self._update_application_status(status='deleting') if not self._destroy_service_instance(): logger.debug("Delete service {} failed.".format(self.service_name)) if not self._destroy_controller_instance(): logger.debug("Delete controller {} failed.".format( self.controller_name)) if not self._destroy_pods_instance(): logger.debug("Delete pods with label 'app={}' failed.".format( self.controller_name)) self._update_application_status(status='deleted') self._umount_volume() # delete autoscaler if self.application.is_autoscaler: autoscaler_destroyer = AutoScalerDestroyer(self.application) autoscaler_destroyer.delete_autoscaler() self._delete_application_metadata() self._delete_port_metadata() self._delete_environments() def _destroy_service_instance(self): return self.kubeclient.delete_service(namespace=self.namespace, name=self.service_name) def _destroy_controller_instance(self): return self.kubeclient.delete_controller(namespace=self.namespace, name=self.controller_name) def _destroy_pods_instance(self): pods = self.kubeclient.list_pods(namespace=self.namespace, label="app={}".format(self.controller_name)) logger.debug(pods) res = True for pod in pods: flag = self.kubeclient.delete_pod(namespace=self.namespace, name=pod) if not flag: res = False return res def _update_application_status(self, status): self.application.status = status self.application.save() def _delete_application_metadata(self): logger.debug("delete application medatada.") self.application.delete() def _delete_port_metadata(self): logger.debug("delete port metadata.") ports = Port.objects.filter(app=self.application) for port in ports: logger.debug("delete port {} metadata.".format(port.name)) port.delete() def _delete_environments(self): envs = Environment.objects.filter(app=self.application) for env in envs: env.delete() def _umount_volume(self): """ Umount volumes which mounted on application. """ volumes = Volume.objects.filter(app=self.application) for volume in volumes: logger.debug("umount volume {}-{} from application {}.".format( volume.project.name, volume.name, self.application_name)) volume.app = None volume.mount_path = None volume.save()
def test_delete_autoscaler(self): beta_client = KubeClient("http://192.168.0.10:8080/apis/extensions/v1beta1/") res = beta_client.delete_autoscaler('user', 'project0-nginx-test') print(res)
class ApplicationBuilder(object): """ ApplicationBuilder is a builder to create an appliction from an image. You should offer many necessary arguments. Parameters: image_name: the image name for the container. tcp_ports: a dict, the tcp ports of the containers. For example: { "http": 80, "https": 443} udp_ports: a dict, the udp ports of the containers. commands: the commands which the container runs when start. envs: a dict for example: {"MYSQL_HOST": "localhost", "PORT": "3306"} volumes: a dict, for example: [{"volume": id, "mount_path": path}] """ namespace = None application = None image_name = None tcp_ports = None udp_ports = None commands = None args = None envs = None is_public = False volumes = None def __init__(self, application, image_name, tcp_ports=None, udp_ports=None, commands=None, args=None, envs=None, is_public=False, volumes=None, min_replicas=None, max_replicas=None, cpu_target=None): self.kubeclient = KubeClient("http://{}:{}{}".format( settings.MASTER_IP, settings.K8S_PORT, settings.K8S_API_PATH)) self.application = application self.namespace = self.application.image.project.name self.application_name = get_application_instance_name(self.application) self.image_name = image_name self.tcp_ports = tcp_ports self.udp_ports = udp_ports self.commands = commands self.args = args self.envs = envs self.is_public = is_public self.volumes = volumes # Compute the resource limit of the application resource_limit = self.application.resource_limit self.cpu = str(resource_limit.cpu) + resource_limit.cpu_unit self.memory = str(resource_limit.memory) + resource_limit.memory_unit # autoscaler if self.application.is_autoscaler: self.min_replicas = int(min_replicas) self.max_replicas = int(max_replicas) self.cpu_target = int(cpu_target) logger.debug( str(self.min_replicas) + " " + str(self.max_replicas) + " " + str(self.cpu_target)) def create_application(self): """ Create application by multiple threading. """ creating_thread = Thread(target=self._create_application) creating_thread.start() def _create_application(self): """ First create a replicationcontroller, then create a service, update database at last. """ logger.info( 'Create an application {} in namespace {} by image {}.'.format( self.application_name, self.namespace, self.image_name)) if not self._create_controller(): logger.debug('Create controller {} failed.'.format( self.application_name)) logger.info( 'Create an application {} in namespace {} failed.'.format( self.application_name, self.namespace, self.image_name)) self._update_application_metadata(status='error') return None if self.tcp_ports or self.udp_ports: if not self._create_service(): logger.debug('Create service {} failed.'.format( self.application_name)) logger.info( 'Create an application {} in namespace {} failed.'.format( self.application_name, self.namespace, self.image_name)) self._update_application_metadata(status='error') return None internal_ip, ports = self._get_service_ip_and_ports() else: internal_ip = None ports = None # update metadata if self.is_public: external_ip = get_optimal_external_ip( namespace=self.namespace, app_name=self.application_name) self._update_application_metadata(status='active', internal_ip=internal_ip, external_ip=external_ip) else: self._update_application_metadata(status='active', internal_ip=internal_ip) # mount volume self._mount_volume_onto_application() # create port metadata self._create_ports_metadata(ports) # create environment metadata self._create_environments_metadata() # create autoscaler if self.application.is_autoscaler: scaler_builder = AutoScalerBuilder(application=self.application, min_replicas=self.min_replicas, max_replicas=self.max_replicas, cpu_target=self.cpu_target) scaler_builder.create_autoscaler() def _create_controller(self): """ Create a replicationcontroller by provided image. """ return self.kubeclient.create_controller( namespace=self.namespace, name=self.application_name, image_name=self.image_name, cpu=self.cpu, memory=self.memory, replicas=self.application.replicas, tcp_ports=self.tcp_ports, udp_ports=self.udp_ports, commands=self.commands, args=self.args, envs=self.envs, volumes=self._get_volume_names_and_path()) def _create_service(self): """ Create a service on the replicationcontroller. """ return self.kubeclient.create_service( namespace=self.namespace, name=self.application_name, tcp_ports=self.tcp_ports, udp_ports=self.udp_ports, is_public=self.is_public, session_affinity=self.application.session_affinity) def _get_service_ip_and_ports(self): """ Get internal_ip and ports of the service. """ response = self.kubeclient.get_service_details(self.namespace, self.application_name) return (response['spec']['clusterIP'], response['spec']['ports']) def _update_application_metadata(self, status=None, internal_ip=None, external_ip=None): """ Update the application metadata. """ if status: self.application.status = status if internal_ip: self.application.internal_ip = internal_ip if external_ip: self.application.external_ip = external_ip self.application.save() def _create_ports_metadata(self, ports): """ Create ports metadata for application. """ if not ports: return None for port_dict in ports: port = Port(app=self.application, name=port_dict['name'], protocol=port_dict['protocol'], external_port=port_dict.get('nodePort', None), internal_port=port_dict['port']) port.save() def _create_environments_metadata(self): """ Create environment metadata for application. """ if not self.envs: return None for name, value in self.envs.items(): env = Environment(app=self.application, name=name, value=value) env.save() def _mount_volume_onto_application(self): """ Edit the metadata, Mount volumes onto this application. """ if not self.volumes: return None for volume_item in self.volumes: volume = Volume.objects.get(id=volume_item['volume']) logger.debug("mount volume {} onto application {}.".format( volume.name, self.application_name)) volume.app = self.application volume.mount_path = volume_item['mount_path'] volume.save() def _get_volume_names_and_path(self): """ Return the volume names from volume ids. The true volume instance name is "project_name-volume_name". """ if not self.volumes: return None volume_name_path = {} for volume_item in self.volumes: volume = Volume.objects.get(id=int(volume_item['volume'])) volume_name = "{}-{}".format(self.namespace, volume.name) volume_name_path[volume_name] = volume_item['mount_path'] logger.debug(volume_name_path) return volume_name_path