def get(current_user, workspaceId, projectId):
    """
    Get a service by service id or project id
    :return: Http Json response
    """
    serviceId = request.args.get('serviceId')
    if serviceId:
        # Get by Service ID
        service = Service.get_by_id(serviceId)
        if service:
            return {
                'serviceType': service.serviceType,
                'id': service._id,
                'createdBy': service.createdBy,
                'createdOn': service.createdOn,
                'isActive': service.isActive,
                'serviceMeta': service.serviceMeta
            }
        else:
            return response('failed', 'service not found', 404)
    else:
        # Get by Project ID
        project = Project.get_by_id(projectId)
        services = project.services
        payload = []
        for service_id in services:
            service = Service.get_by_id(service_id)
            payload.append({"id": service_id,
                            "serviceType": service.serviceType,
                            "isActive": service.isActive,
                            "serviceMeta": service.serviceMeta})

        return {'services': payload}
Пример #2
0
def get(current_user, workspaceId, projectId):
    """
    Get a project by project id
    :return: Http Json response
    """
    project = Project.get_by_id(projectId)

    if project:
        services = project.services
        srv_payload = []
        for sid in services:
            srv = Service.get_by_id(sid)
            if srv:
                srv_obj = {
                    'id': srv._id,
                    'serviceType': srv.serviceType,
                    'serviceMeta': srv.serviceMeta,
                    'isActive': srv.isActive
                }
                srv_payload.append(srv_obj)
        return {
            'name': project.name,
            'id': project._id,
            'createdBy': project.createdBy,
            'createdOn': project.createdOn,
            'isActive': project.isActive,
            'services': srv_payload,
            'timezone': project.timezone
        }
    else:
        return response('failed', 'project not found', 404)
Пример #3
0
    def post(self, project_id, app_id):
        """
        """

        app_memory_schema = MetricsSchema()
        app_query_data = request.get_json()

        validated_query_data, errors = app_memory_schema.load(app_query_data)

        if errors:
            return dict(status='fail', message=errors), 400

        current_time = datetime.datetime.now()
        yesterday_time = current_time + datetime.timedelta(days=-1)

        start = validated_query_data.get('start', yesterday_time.timestamp())
        end = validated_query_data.get('end', current_time.timestamp())
        step = validated_query_data.get('step', '1h')

        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        app = App.get_by_id(app_id)

        if not app:
            return dict(status='fail', message=f'App {app_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='Unauthorised'), 403

        app_alias = app.alias
        namespace = project.alias

        prom_memory_data = prometheus.query_rang(
            start=start,
            end=end,
            step=step,
            metric=
            'sum(rate(container_memory_usage_bytes{container_name!="POD", image!="",pod=~"'
            + app_alias + '.*", namespace="' + namespace + '"}[5m]))')

        new_data = json.loads(prom_memory_data)
        final_data_list = []
        try:
            for value in new_data["data"]["result"][0]["values"]:
                mem_case = {
                    'timestamp': float(value[0]),
                    'value': float(value[1])
                }
                final_data_list.append(mem_case)
        except:
            return dict(status='fail', message='No values found'), 404

        return dict(status='success', data=dict(values=final_data_list)), 200
def get(current_user):
    """
    Get a workspace by workspace id
    :return: Http Json response
    """
    wsp_id = request.args.get('workspaceId')
    if wsp_id in current_user.workspaces:
        workspace = Workspace.get_by_id(wsp_id)
        if workspace:
            projects = workspace.projects
            prj_payload = []
            for pid in projects:
                prj = Project.get_by_id(pid)
                if prj:
                    prj_name = prj.name
                    prj_obj = {'id': pid, 'name': prj_name}
                    prj_payload.append(prj_obj)
            return {
                'name': workspace.name,
                'id': workspace._id,
                'createdBy': workspace.createdBy,
                'createdOn': workspace.createdOn,
                'isActive': workspace.isActive,
                'projects': prj_payload
            }
        else:
            return response('failed', 'workspace not found', 404)
    else:
        return response('failed', 'user not authorized to access workspace',
                        403)
def create(current_user, workspaceId, projectId):
    """
        Create a service. Reuires login
    """
    if request.content_type == 'application/json':
        post_data = request.get_json(force=True)
        required_keys = ['serviceType', 'serviceMeta']
        if all(name in post_data for name in required_keys):

            service = Service(serviceType=post_data.get('serviceType'),
                              serviceMeta=post_data.get('serviceMeta'),
                              projectId=projectId,
                              createdBy=current_user.email_id)

            service.create()

            # add to project
            project = Project.get_by_id(projectId)
            project.services.append(service._id)
            project.save()

            # Replcing _id with id
            service_obj = json.loads(service.to_json())
            service_obj['id'] = service_obj['_id']
            service_obj.pop('_id', None)

            return response_with_obj('success', 'Service created successfully', service_obj, 200)
        else:
            return response('failed', 'Required data not found in POST body.', 402)

    return response('failed', 'Content-type must be json', 402)
Пример #6
0
    def post(self, project_id, database_id):
        """
        """
        database_schema = ProjectDatabaseSchema()
        database_data = request.get_json()

        validated_database_data, errors = database_schema.load(
            database_data, partial=("database_flavour_name", ))

        if errors:
            return dict(status="fail", message=errors), 400

        new_database_password = validated_database_data.get('password', None)

        project = Project.get_by_id(project_id)
        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        database_existant = ProjectDatabase.get_by_id(database_id)
        if not database_existant:
            return dict(
                status="fail",
                message=f"Database with id {database_id} not found."), 404

        database_flavour_name = database_existant.database_flavour_name

        db_flavour = get_db_flavour(database_flavour_name)

        if not db_flavour:
            return dict(
                status="fail",
                message=
                f"Database flavour with name {database_existant.database_flavour_name} is not mysql or postgres."
            ), 409

        # Reset db password
        database_service = db_flavour['class']
        database_connection = database_service.check_db_connection()

        if not database_connection:
            return dict(
                status="fail",
                message=f"Failed to connect to the database service"), 500

        reset_database_password = database_service.reset_password(
            user=database_existant.user, password=new_database_password)

        if not reset_database_password:
            return dict(status="fail",
                        message=f"Unable to reset database password"), 500

        updated = ProjectDatabase.update(database_existant,
                                         **validated_database_data)
        if not updated:
            return dict(status='fail', message='internal server error'), 500

        return dict(status='success',
                    message="Database password reset Successfully"), 200
Пример #7
0
    def post(self, project_id, app_id):

        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        app_memory_schema = MetricsSchema()
        app_cpu_data = request.get_json()

        validated_query_data, errors = app_memory_schema.load(app_cpu_data)

        if errors:
            return dict(status='fail', message=errors), 400

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='unauthorised'), 403

        # Check app from db
        app = App.get_by_id(app_id)

        if not app:
            return dict(status='fail', message=f'app {app_id} not found'), 404

        # Get current time
        current_time = datetime.datetime.now()
        yesterday = current_time + datetime.timedelta(days=-1)
        namespace = project.alias
        app_alias = app.alias

        prometheus = Prometheus()

        start = validated_query_data.get('start', yesterday.timestamp())
        end = validated_query_data.get('end', current_time.timestamp())
        step = validated_query_data.get('step', '1h')

        prom_data = prometheus.query_rang(
            start=start,
            end=end,
            step=step,
            metric=
            'sum(rate(container_cpu_usage_seconds_total{container!="POD", image!="", namespace="'
            + namespace + '", pod=~"' + app_alias + '.*"}[5m]))')
        #  change array values to json"values"
        new_data = json.loads(prom_data)
        cpu_data_list = []
        try:
            for value in new_data["data"]["result"][0]["values"]:
                case = {'timestamp': float(value[0]), 'value': float(value[1])}
                cpu_data_list.append(case)
        except:
            return dict(status='fail', message='No values found'), 404

        return dict(status='success', data=dict(values=cpu_data_list)), 200
Пример #8
0
    def patch(self, project_id):
        """
        """

        try:
            current_user_id = get_jwt_identity()
            current_user_roles = get_jwt_claims()['roles']

            project_schema = ProjectSchema(only=("name", "description"),
                                           partial=True)

            project_data = request.get_json()

            validate_project_data, errors = project_schema.load(project_data)

            existing_project = False

            if errors:
                return dict(status='fail', message=errors), 400

            if 'name' in validate_project_data:
                existing_project = Project.find_first(
                    name=validate_project_data['name'],
                    owner_id=current_user_id)

            if existing_project:
                return dict(
                    status='fail',
                    message=
                    f'project with name {validate_project_data["name"]} already exists'
                ), 409

            project = Project.get_by_id(project_id)

            if not project:
                return dict(status='fail',
                            message=f'Project {project_id} not found'), 404

            if not is_owner_or_admin(project, current_user_id,
                                     current_user_roles):
                return dict(status='fail', message='unauthorised'), 403

            updated = Project.update(project, **validate_project_data)

            if not updated:
                return dict(status='fail',
                            message='internal server error'), 500

            return dict(
                status='success',
                message=f'project {project_id} updated successfully'), 200

        except Exception as e:
            return dict(status='fail', message=str(e)), 500
Пример #9
0
    def delete(self, project_id):
        """
        """

        try:
            current_user_id = get_jwt_identity()
            current_user_roles = get_jwt_claims()['roles']

            project = Project.get_by_id(project_id)

            if not project:
                return dict(status='fail',
                            message=f'project {project_id} not found'), 404

            if not is_owner_or_admin(project, current_user_id,
                                     current_user_roles):
                return dict(status='fail', message='unauthorised'), 403

            # get cluster for the project
            cluster = Cluster.get_by_id(project.cluster_id)

            if not cluster:
                return dict(status='fail', message='cluster not found'), 500

            kube_host = cluster.host
            kube_token = cluster.token

            kube_client = create_kube_clients(kube_host, kube_token)

            # get corresponding namespace

            namespace = kube_client.kube.read_namespace(project.alias)

            # delete namespace if it exists
            if namespace:
                kube_client.kube.delete_namespace(project.alias)

            # To do; change delete to a soft delete
            deleted = project.delete()

            if not deleted:
                return dict(status='fail', message='deletion failed'), 500

            return dict(
                status='success',
                message=f'project {project_id} deleted successfully'), 200

        except client.rest.ApiException as e:
            return dict(status='fail', message=e.reason), e.status

        except Exception as e:
            return dict(status='fail', message=str(e)), 500
Пример #10
0
    def delete(self, project_id, database_id):
        """
        """
        database_schema = ProjectDatabaseSchema()

        project = Project.get_by_id(project_id)
        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        database_existant = ProjectDatabase.get_by_id(database_id)

        if not database_existant:
            return dict(
                status="fail",
                message=f"Database with id {database_id} not found."), 404

        database_flavour_name = database_existant.database_flavour_name

        db_flavour = get_db_flavour(database_flavour_name)

        if not db_flavour:
            return dict(
                status="fail",
                message=
                f"Database flavour with name {database_existant.database_flavour_name} is not mysql or postgres."
            ), 409

        # Delete the database
        database_service = db_flavour['class']
        database_connection = database_service.check_db_connection()

        if not database_connection:
            return dict(
                status="fail",
                message=f"Failed to connect to the database service"), 500

        delete_database = database_service.delete_database(
            database_existant.name)

        if not delete_database:
            return dict(status="fail",
                        message=f"Unable to delete database"), 500

        # Delete database record from database
        deleted_database = database_existant.delete()

        if not deleted_database:
            return dict(status='fail', message=f'Internal Server Error'), 500

        return dict(status='success',
                    message="Database Successfully deleted"), 200
Пример #11
0
    def get(self, project_id):
        """
        """
        database_schema = ProjectDatabaseSchema(many=True)

        project = Project.get_by_id(project_id)
        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        databases = ProjectDatabase.find_all(project_id=project_id)

        database_data, errors = database_schema.dumps(databases)

        if errors:
            return dict(status='fail', message=errors), 500

        database_data_list = json.loads(database_data)

        # Check the database status on host
        for database in database_data_list:
            flavour_name = database['database_flavour_name']
            if not flavour_name:
                flavour_name = "mysql"

            db_flavour = get_db_flavour(flavour_name)
            database_service = db_flavour['class']

            try:
                database_connection = database_service.create_db_connection(
                    user=database['user'],
                    password=database['password'],
                    db_name=database['name'])

                if not database_connection:
                    db_status = False
                else:
                    db_status = True
            except:
                db_status = False
            finally:
                if database_connection:
                    if database_service == MysqlDbService():
                        if database_connection.is_connected():
                            database_connection.close()
                        else:
                            database_connection.close()

            database['db_status'] = db_status

        return dict(status='success',
                    data=dict(databases=database_data_list)), 200
Пример #12
0
    def post(self, project_id, app_id):

        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='unauthorised'), 403

        # Check app from db
        app = App.get_by_id(app_id)

        if not app:
            return dict(status='fail', message=f'app {app_id} not found'), 404

        namespace = project.alias
        app_alias = app.alias

        prometheus = Prometheus()

        try:
            prom_data = prometheus.query(
                metric=
                'sum(kube_persistentvolumeclaim_resource_requests_storage_bytes{namespace="'
                + namespace + '", persistentvolumeclaim=~"' + app_alias +
                '.*"})')
            #  change array values to json
            new_data = json.loads(prom_data)
            values = new_data["data"]

            percentage_data = prometheus.query(
                metric='100*(kubelet_volume_stats_used_bytes{namespace="' +
                namespace + '", persistentvolumeclaim=~"' + app_alias +
                '.*"}/kubelet_volume_stats_capacity_bytes{namespace="' +
                namespace + '", persistentvolumeclaim=~"' + app_alias +
                '.*"})')

            data = json.loads(percentage_data)
            volume_perc_value = data["data"]
        except:
            return dict(status='fail', message='No values found'), 404

        return dict(status='success',
                    data=dict(storage_capacity=values,
                              storage_percentage_usage=volume_perc_value)), 200
Пример #13
0
    def post(self, project_id, database_id):
        """
        Reset Database
        """
        database_schema = ProjectDatabaseSchema()

        project = Project.get_by_id(project_id)
        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        database_existant = ProjectDatabase.get_by_id(database_id)

        if not database_existant:
            return dict(
                status="fail",
                message=f"Database with id {database_id} not found."), 404

        # Reset the database
        db_flavour = get_db_flavour(database_existant.database_flavour_name)

        if not db_flavour:
            return dict(
                status="fail",
                message=
                f"Database with flavour name {database_existant.database_flavour_name} is not mysql or postgres."
            ), 409

        database_service = db_flavour['class']
        database_connection = database_service.check_db_connection()

        if not database_connection:
            return dict(
                status="fail",
                message=f"Failed to connect to the database service"), 500

        reset_database = database_service.reset_database(
            db_name=database_existant.name,
            user=database_existant.user,
            password=database_existant.password)

        if not reset_database:
            return dict(status="fail",
                        message=f"Unable to reset database"), 500

        return dict(status='success',
                    message="Database Reset Successfully"), 200
Пример #14
0
    def publish(self, projectId, current_user, priceContract):
        """
        Publish Bot - Triggers Billing
        TODO
        """
        self.publishedOn = util.get_current_time()

        if not self.isPublished:
            self.isPublished = True
            ##Create a bot service
            serviceMeta = self.playgroundMeta
            serviceMeta["priceContract"] = priceContract
            service = Service(serviceType='bot',
                              serviceMeta=serviceMeta,
                              projectId=projectId,
                              createdBy=current_user.email_id)
            service.create()

            self.publishedServiceId = service._id

            #add to project
            project = Project.get_by_id(projectId)
            project.services.append(service._id)
            project.save()

            self.save()

        else:
            #update service
            service = Service.get_by_id(self.publishedServiceId)
            servicePriceContract = service.serviceMeta.get(
                "priceContract", {})  #get exisitng price contract
            serviceMeta = self.playgroundMeta  #copy new playground meta
            serviceMeta[
                "priceContract"] = servicePriceContract  #add priceContract to service Meta
            service.serviceMeta = serviceMeta  #set new service meta
            service.save()

            self.save()

        return service._id
Пример #15
0
def update(current_user, workspaceId, projectId):
    """
        Update Project
    """
    if request.content_type == 'application/json':
        post_data = request.get_json()
        prj = Project.get_by_id(projectId)
        if prj:
            prj.update_project(post_data)
            res_payload = {
                'name': prj.name,
                'id': prj._id,
                'createdBy': prj.createdBy,
                'createdOn': prj.createdOn,
                'isActive': prj.isActive,
                'timezone': prj.timezone
            }
            return response_with_obj('success', 'Project updated successfully',
                                     res_payload, 200)
        else:
            response('failed', 'Project not found', 402)
    else:
        return response('failed', 'Content-type must be json', 402)
Пример #16
0
    def get(self, project_id):
        """
        """
        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        project_schema = ProjectSchema()

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='unauthorised'), 403

        project_data, errors = project_schema.dumps(project)

        if errors:
            return dict(status='fail', message=errors), 500

        return dict(status='success',
                    data=dict(project=json.loads(project_data))), 200
Пример #17
0
def manage_oerview(current_user, workspaceId, projectId):
    project = Project.get_by_id(projectId)

    playgrounds = Playground.get_by_project_id(projectId)
    playgroundsPayload = []
    srv_to_playground = {}
    for playground in playgrounds:
        if playground.isPublished and playground.publishedServiceId:
            srv_to_playground[playground.publishedServiceId] = playground._id
        else:
            if "template" in playground.playgroundMeta.keys():
                playground.playgroundMeta.pop("template")
            playgroundsPayload.append(
                {
                    "id": playground._id,
                    "createdBy": playground.createdBy,
                    "createdOn": playground.createdOn,
                    "lastModified": playground.lastModified,
                    "playgroundMeta": playground.playgroundMeta,
                    "parentMarketplaceBot": playground.parentMarketplaceBot
                }
            )

    services = project.services
    servicesPayload = []
    serviceIds = []
    integrations_to_bot = {}
    for service_id in services:
        service = Service.get_by_id(service_id)

        if "template" in service.serviceMeta.keys():
            service.serviceMeta.pop("template")

        if service.serviceType == "textChannel" or service.serviceType == "phone":
            if not integrations_to_bot.get(service.serviceMeta.get('parentBot', service_id)):
                integrations_to_bot[service.serviceMeta.get('parentBot', service_id)] = []
            integrations_to_bot[service.serviceMeta.get('parentBot', service_id)].append({"id": service_id,
                                                                                          "serviceType": service.serviceType,
                                                                                          "isActive": service.isActive,
                                                                                          "serviceMeta": service.serviceMeta})

        elif service.serviceType == "bot":
            servicesPayload.append({"id": service_id,
                                    "serviceType": service.serviceType,
                                    "isActive": service.isActive,
                                    "playgroundId": srv_to_playground.get(service_id),
                                    "serviceMeta": service.serviceMeta})
            serviceIds.append(service._id)

    for item in servicesPayload:
        item["integrations"] = integrations_to_bot.get(item['id'], [])

    combinedPayload = {
        "playgrounds": playgroundsPayload,
        "services": servicesPayload
    }

    return make_response(jsonify({
        'status': "success",
        'message': "Payload retrieved successfully",
        'service': combinedPayload
    })), 200
Пример #18
0
def messenger_integration(current_user, workspaceId, projectId):
    page_token = request.get_json(force=True).get('pageToken')
    page_id = request.get_json(force=True).get('pageId')
    page_name = request.get_json(force=True).get('pageName')
    bot_id = request.get_json(force=True).get('botId')
    language_code = request.get_json(force=True).get('languageCode', 'en-US')

    if all([page_token, page_id, page_name, bot_id, language_code]):

        # check if integrations already exist for the facebook page
        existingIntegrations = Service.objects(__raw__={
            'serviceMeta.channelId': str(page_id),
            'serviceMeta.channel': 'messenger',
            'isRemoved': False
        }).count()
        # if integrations exist, disable them
        print("existingIntegrations", existingIntegrations)
        if existingIntegrations:
            service = Service.objects(__raw__={
                'serviceMeta.channelId': str(page_id),
                'serviceMeta.channel': 'messenger',
                'isRemoved': False
            }).first()
            service.isActive = True
            service.save()

            # Replcing _id with id
            service_obj = json.loads(service.to_json())
            service_obj['id'] = service_obj['_id']
            service_obj.pop('_id', None)

            return response_with_obj('success', 'Existing service activated successfully', service_obj, 200)

        else:
            # create new service
            service = Service(serviceType='textChannel',
                              serviceMeta={
                                  'channel': 'messenger',
                                  'channelId': page_id,
                                  'channelName': page_name,
                                  'parentBot': bot_id,
                                  'accessToken': page_token,
                                  'languageCode': language_code
                              },
                              projectId=projectId,
                              createdBy=current_user.email_id)

            service.create()

            # add to project
            project = Project.get_by_id(projectId)
            project.services.append(service._id)
            project.save()

            # Replcing _id with id
            service_obj = json.loads(service.to_json())
            service_obj['id'] = service_obj['_id']
            service_obj.pop('_id', None)

            return response_with_obj('success', 'Service created successfully', service_obj, 200)

    else:
        return response('failed', 'Required data not found in POST body.', 402)
Пример #19
0
    def post(self, project_id):
        """
        """
        database_schema = ProjectDatabaseSchema()

        databases_data = request.get_json()

        credentials = generate_db_credentials()

        validated_database_data, errors = database_schema.load(databases_data)

        if errors:
            return dict(status="fail", message=errors), 400

        database_flavour_name = validated_database_data.get(
            'database_flavour_name', None)

        db_flavour = get_db_flavour(database_flavour_name)

        if not db_flavour:
            return dict(
                status="fail",
                message=
                f"Database flavour with name {database_flavour_name} is not mysql or postgres."
            ), 409

        database_name = validated_database_data.get('name', credentials.name)
        database_user = validated_database_data.get('user', credentials.user)
        database_password = validated_database_data.get(
            'password', credentials.password)

        new_database_info = dict(user=database_user,
                                 password=database_password,
                                 project_id=project_id,
                                 name=database_name,
                                 database_flavour_name=database_flavour_name,
                                 host=db_flavour['host'],
                                 port=db_flavour['port'])

        validated_database_data, errors = database_schema.load(
            new_database_info)

        if errors:
            return dict(status="fail", message=errors), 400

        project = Project.get_by_id(project_id)
        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        validated_database_data['project_id'] = project_id

        database_existant = ProjectDatabase.find_first(name=database_name)

        if database_existant:
            return dict(
                status="fail",
                message=f"Database {database_name} Already Exists."), 400

        database_user_existant = ProjectDatabase.find_first(user=database_user)

        if database_user_existant:
            return dict(
                status="fail",
                message=f"Database user {database_user} Already Exists."), 400

        # Create the database
        database_service = db_flavour['class']
        database_connection = database_service.check_db_connection()

        if not database_connection:
            return dict(
                status="fail",
                message=f"Failed to connect to the database service"), 500

        create_database = database_service.create_database(
            db_name=database_name,
            user=database_user,
            password=database_password)

        if not create_database:
            return dict(status="fail",
                        message=f"Unable to create database"), 500

        # Save database credentials
        database = ProjectDatabase(**validated_database_data)
        saved_database = database.save()

        if not saved_database:
            return dict(status='fail', message=f'Internal Server Error'), 500

        new_database_data, errors = database_schema.dumps(database)

        return dict(status='success',
                    data=dict(database=json.loads(new_database_data))), 201
Пример #20
0
    def post(self, project_id):
        """
        """

        resource_registry = {
            'db_deployment': False,
            'db_service': False,
            'image_pull_secret': False,
            'app_deployment': False,
            'app_service': False,
            'ingress_entry': False
        }

        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        app_schema = AppSchema()

        app_data = request.get_json()

        validated_app_data, errors = app_schema.load(app_data,
                                                     partial=("project_id", ))

        if errors:
            return dict(status='fail', message=errors), 400

        existing_app = App.find_first(name=validated_app_data['name'],
                                      project_id=project_id)

        if existing_app:
            return dict(
                status='fail',
                message=
                f'App with name {validated_app_data["name"]} already exists'
            ), 409

        validated_app_data['port'] = validated_app_data.get('port', 80)

        app_name = validated_app_data['name']
        app_alias = create_alias(validated_app_data['name'])
        app_image = validated_app_data['image']
        command = validated_app_data.get('command', None)
        # env_vars = validated_app_data['env_vars']
        env_vars = validated_app_data.get('env_vars', None)
        private_repo = validated_app_data.get('private_image', False)
        docker_server = validated_app_data.get('docker_server', None)
        docker_username = validated_app_data.get('docker_username', None)
        docker_password = validated_app_data.get('docker_password', None)
        docker_email = validated_app_data.get('docker_email', None)
        replicas = validated_app_data.get('replicas', 1)
        app_port = validated_app_data.get('port', None)
        image_pull_secret = None

        command = command.split() if command else None

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='Unauthorised'), 403

        cluster = project.cluster
        namespace = project.alias

        if not cluster:
            return dict(status='fail', message="Invalid Cluster"), 500

        # check if app already exists
        app = App.find_first(**{'name': app_name})

        if app:
            return dict(status='fail',
                        message=f'App {app_name} already exists'), 409

        kube_host = cluster.host
        kube_token = cluster.token
        service_host = urlsplit(kube_host).hostname

        kube_client = create_kube_clients(kube_host, kube_token)

        try:

            # create the app
            new_app = App(name=app_name,
                          image=app_image,
                          project_id=project_id,
                          alias=app_alias,
                          port=app_port)

            if private_repo:

                # handle gcr credentials
                if 'gcr' in docker_server and docker_username == '_json_key':
                    docker_password = json.dumps(
                        json.loads(base64.b64decode(docker_password)))

                # create image pull secrets
                authstring = base64.b64encode(
                    f'{docker_username}:{docker_password}'.encode("utf-8"))

                secret_dict = dict(
                    auths={
                        docker_server: {
                            "username": docker_username,
                            "password": docker_password,
                            "email": docker_email,
                            "auth": str(authstring, "utf-8")
                        }
                    })

                secret_b64 = base64.b64encode(
                    json.dumps(secret_dict).encode("utf-8"))

                secret_body = client.V1Secret(
                    metadata=client.V1ObjectMeta(name=app_alias),
                    type='kubernetes.io/dockerconfigjson',
                    data={'.dockerconfigjson': str(secret_b64, "utf-8")})

                kube_client.kube.create_namespaced_secret(
                    namespace=namespace,
                    body=secret_body,
                    _preload_content=False)

                # update registry
                resource_registry['image_pull_secret'] = True

                image_pull_secret = client.V1LocalObjectReference(
                    name=app_alias)

            # create app deployment's pvc meta and spec
            # pvc_name = f'{app_alias}-pvc'
            # pvc_meta = client.V1ObjectMeta(name=pvc_name)

            # access_modes = ['ReadWriteOnce']
            # storage_class = 'openebs-standard'
            # resources = client.V1ResourceRequirements(
            #     requests=dict(storage='1Gi'))

            # pvc_spec = client.V1PersistentVolumeClaimSpec(
            #     access_modes=access_modes, resources=resources, storage_class_name=storage_class)

            # Create a PVC
            # pvc = client.V1PersistentVolumeClaim(
            #     api_version="v1",
            #     kind="PersistentVolumeClaim",
            #     metadata=pvc_meta,
            #     spec=pvc_spec
            # )

            # kube_client.kube.create_namespaced_persistent_volume_claim(
            #     namespace=namespace,
            #     body=pvc
            # )

            # create deployment
            dep_name = f'{app_alias}-deployment'

            # # EnvVar
            env = []
            if env_vars:
                for key, value in env_vars.items():
                    env.append(client.V1EnvVar(name=str(key),
                                               value=str(value)))

            # pod template
            container = client.V1Container(
                name=app_alias,
                image=app_image,
                ports=[client.V1ContainerPort(container_port=app_port)],
                env=env,
                command=command
                # volume_mounts=[client.V1VolumeMount(mount_path="/data", name=dep_name)]
            )

            #pod volumes
            # volumes = client.V1Volume(
            #     name=dep_name
            #     # persistent_volume_claim=client.V1PersistentVolumeClaimVolumeSource(claim_name=pvc_name)
            # )

            # spec
            template = client.V1PodTemplateSpec(
                metadata=client.V1ObjectMeta(labels={'app': app_alias}),
                spec=client.V1PodSpec(containers=[container],
                                      image_pull_secrets=[image_pull_secret]
                                      # volumes=[volumes]
                                      ))

            # spec of deployment
            spec = client.V1DeploymentSpec(
                replicas=replicas,
                template=template,
                selector={'matchLabels': {
                    'app': app_alias
                }})

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

            # create deployment in  cluster

            kube_client.appsv1_api.create_namespaced_deployment(
                body=deployment, namespace=namespace, _preload_content=False)

            # update registry
            resource_registry['app_deployment'] = True

            # create service in the cluster
            service_name = f'{app_alias}-service'

            service_meta = client.V1ObjectMeta(name=service_name,
                                               labels={'app': app_alias})

            service_spec = client.V1ServiceSpec(
                type='ClusterIP',
                ports=[client.V1ServicePort(port=3000, target_port=app_port)],
                selector={'app': app_alias})

            service = client.V1Service(metadata=service_meta,
                                       spec=service_spec)

            kube_client.kube.create_namespaced_service(namespace=namespace,
                                                       body=service,
                                                       _preload_content=False)

            # update resource registry
            resource_registry['app_service'] = True

            # subdomain for the app
            # sub_domain = f'{app_alias}.cranecloud.io'
            sub_domain = get_app_subdomain(app_alias)

            # create new ingres rule for the application
            new_ingress_backend = client.ExtensionsV1beta1IngressBackend(
                service_name=service_name, service_port=3000)

            new_ingress_rule = client.ExtensionsV1beta1IngressRule(
                host=sub_domain,
                http=client.ExtensionsV1beta1HTTPIngressRuleValue(paths=[
                    client.ExtensionsV1beta1HTTPIngressPath(
                        path="", backend=new_ingress_backend)
                ]))

            ingress_name = f'{project.alias}-ingress'

            # Check if there is an ingress resource in the namespace, create if not

            ingress_list = kube_client.extension_api.list_namespaced_ingress(
                namespace=namespace).items

            if not ingress_list:

                ingress_meta = client.V1ObjectMeta(name=ingress_name)

                ingress_spec = client.ExtensionsV1beta1IngressSpec(
                    # backend=ingress_backend,
                    rules=[new_ingress_rule])

                ingress_body = client.ExtensionsV1beta1Ingress(
                    metadata=ingress_meta, spec=ingress_spec)

                kube_client.extension_api.create_namespaced_ingress(
                    namespace=namespace, body=ingress_body)

                # update registry
                resource_registry['ingress_entry'] = True
            else:
                # Update ingress with new entry
                ingress = ingress_list[0]

                ingress.spec.rules.append(new_ingress_rule)

                kube_client.extension_api.patch_namespaced_ingress(
                    name=ingress_name, namespace=namespace, body=ingress)

            service_url = f'https://{sub_domain}'

            new_app.url = service_url

            saved = new_app.save()

            if not saved:
                return dict(status='fail',
                            message='Internal Server Error'), 500

            new_app_data, _ = app_schema.dump(new_app)

            return dict(status='success', data=dict(app=new_app_data)), 201

        except client.rest.ApiException as e:
            resource_clean_up(resource_registry, app_alias, namespace,
                              kube_client)
            return dict(status='fail', message=json.loads(e.body)), 500

        except Exception as e:
            resource_clean_up(resource_registry, app_alias, namespace,
                              kube_client)
            return dict(status='fail', message=str(e)), 500
Пример #21
0
    def get(self, project_id, database_id):
        """
        """
        database_schema = ProjectDatabaseSchema()

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'Project with id {project_id} not found'), 404

        database_existant = ProjectDatabase.get_by_id(database_id)

        if not database_existant:
            return dict(
                status="fail",
                message=f"Database with id {database_id} not found."), 404

        database_data, errors = database_schema.dumps(database_existant)

        if errors:
            return dict(status='fail', message=errors), 500

        # Check the database status on host
        flavour_name = database_existant.database_flavour_name
        if not flavour_name:
            flavour_name = "mysql"

        db_flavour = get_db_flavour(flavour_name)

        if not db_flavour:
            return dict(
                status="fail",
                message=
                f"Database with flavour {database_existant.database_flavour_name} is not mysql or postgres."
            ), 409

        database_service = db_flavour['class']

        # Get db status
        try:
            database_connection = database_service.create_db_connection(
                user=database_existant.user,
                password=database_existant.password,
                db_name=database_existant.name)
            if not database_connection:
                db_status = False
            else:
                db_status = True
        except:
            db_status = False
        finally:
            if database_connection:
                if database_service == MysqlDbService():
                    if database_connection.is_connected():
                        database_connection.close()
                    else:
                        database_connection.close()

        database_data_list = json.loads(database_data)
        database_data_list['db_status'] = db_status

        return dict(status='success',
                    data=dict(database=database_data_list)), 200
Пример #22
0
    def post(self, project_id, app_id):

        current_user_id = get_jwt_identity()
        current_user_roles = get_jwt_claims()['roles']

        logs_schema = PodsLogsSchema()
        logs_data = request.get_json()

        validated_query_data, errors = logs_schema.load(logs_data)

        if errors:
            return dict(status='fail', message=errors), 400

        project = Project.get_by_id(project_id)

        if not project:
            return dict(status='fail',
                        message=f'project {project_id} not found'), 404

        if not is_owner_or_admin(project, current_user_id, current_user_roles):
            return dict(status='fail', message='unauthorised'), 403

        # Check app from db
        app = App.get_by_id(app_id)

        if not app:
            return dict(status='fail', message=f'app {app_id} not found'), 404

        cluster = project.cluster
        if not cluster:
            return dict(status='fail', message="Invalid Cluster"), 500

        kube_host = cluster.host
        kube_token = cluster.token
        kube_client = create_kube_clients(kube_host, kube_token)

        namespace = project.alias
        deployment = app.alias

        tail_lines = validated_query_data.get('tail_lines', 100)
        since_seconds = validated_query_data.get('since_seconds', 86400)
        timestamps = validated_query_data.get('timestamps', False)
        ''' Get Replicas sets'''
        replicas = kube_client.appsv1_api.list_namespaced_replica_set(
            namespace).to_dict()
        replicasList = []
        for replica in replicas['items']:
            name = replica['metadata']['name']
            if name.startswith(deployment):
                replicasList.append(name)
        ''' get pods list'''
        pods = kube_client.kube.list_namespaced_pod(namespace)
        podsList = []
        failed_pods = []
        for item in pods.items:
            item = kube_client.api_client.sanitize_for_serialization(item)
            pod_name = item['metadata']['name']

            try:
                status = item['status']['conditions'][1]['status']
            except:
                continue

            for replica in replicasList:
                if pod_name.startswith(replica):
                    if status == 'True':
                        podsList.append(pod_name)
                    else:
                        failed_pods.append(pod_name)
                    continue

            if pod_name.startswith(deployment):
                if status == 'True':
                    podsList.append(pod_name)
                else:
                    state = item['status']['containerStatuses'][0]['state']
                    failed_pods.append(state)
        ''' Get pods logs '''
        pods_logs = []

        for pod in podsList:
            podLogs = kube_client.kube.read_namespaced_pod_log(
                pod,
                namespace,
                pretty=True,
                tail_lines=tail_lines or 100,
                timestamps=timestamps or False,
                since_seconds=since_seconds or 86400)

            if podLogs == '':
                podLogs = kube_client.kube.read_namespaced_pod_log(
                    pod,
                    namespace,
                    pretty=True,
                    tail_lines=tail_lines or 100,
                    timestamps=timestamps or False)
            pods_logs.append(podLogs)

        # Get failed pods infor
        for state in failed_pods:
            if type(state) == dict:
                waiting = state.get('waiting')
                if waiting:
                    try:
                        stop = state['waiting']['message'].index('container')
                        message = state['waiting']['message'][:stop]
                    except:
                        message = state['waiting'].get('message')

                    reason = state['waiting']['reason']
                    pod_infor = f'type\tstatus\treason\t\t\tmessage\n----\t------\t------\t\t\t------\nwaiting\tfailed\t{reason}\t{message}'
                    pods_logs.append(pod_infor)

        if not pods_logs or not pods_logs[0]:
            return dict(status='fail', data=dict(message='No logs found')), 404

        return dict(status='success', data=dict(pods_logs=pods_logs)), 200
Пример #23
0
    def get(self, project_id):
        """
        """
        try:
            current_user_id = get_jwt_identity()
            current_user_roles = get_jwt_claims()['roles']

            app_schema = AppSchema(many=True)

            project = Project.get_by_id(project_id)

            if not project:
                return dict(status='fail',
                            message=f'project {project_id} not found'), 404

            if not is_owner_or_admin(project, current_user_id,
                                     current_user_roles):
                return dict(status='fail', message='Unauthorised'), 403

            cluster = Cluster.get_by_id(project.cluster_id)

            if not cluster:
                return dict(
                    status='fail',
                    message=
                    f'cluster with id {project.cluster_id} does not exist'
                ), 404

            kube_host = cluster.host
            kube_token = cluster.token
            kube_client = create_kube_clients(kube_host, kube_token)

            apps = App.find_all(project_id=project_id)

            apps_data, errors = app_schema.dumps(apps)

            if errors:
                return dict(status='fail', message=errors), 500

            apps_data_list = json.loads(apps_data)

            for app in apps_data_list:
                app_status_object = \
                    kube_client.appsv1_api.read_namespaced_deployment_status(
                        app['alias']+"-deployment", project.alias)

                app_deployment_status_conditions = app_status_object.status.conditions

                for deplyoment_status_condition in app_deployment_status_conditions:
                    if deplyoment_status_condition.type == "Available":
                        app_deployment_status = deplyoment_status_condition.status

                try:
                    app_db_status_object = \
                        kube_client.appsv1_api.read_namespaced_deployment_status(
                            app['alias']+"-postgres-db", project.alias)

                    app_db_state_conditions = app_db_status_object.status.conditions

                    for app_db_condition in app_db_state_conditions:
                        if app_db_condition.type == "Available":
                            app_db_status = app_db_condition.status

                except client.rest.ApiException:
                    app_db_status = None

                if app_deployment_status and not app_db_status:
                    if app_deployment_status == "True":
                        app['app_running_status'] = "running"
                    else:
                        app['app_running_status'] = "failed"
                elif app_deployment_status and app_db_status:
                    if app_deployment_status == "True" and app_db_status == "True":
                        app['app_running_status'] = "running"
                    else:
                        app['app_running_status'] = "failed"
                else:
                    app['app_running_status'] = "unknown"

            return dict(status='success', data=dict(apps=apps_data_list)), 200

        except client.rest.ApiException as exc:
            return dict(status='fail', message=exc.reason), exc.status

        except Exception as exc:
            return dict(status='fail', message=str(exc)), 500