Skip to content

Commit

Permalink
Merge pull request #32 from cloudblue/feature/LITE-28066-User-can-see…
Browse files Browse the repository at this point in the history
…-the-list-of-the-dep-req-across-all-deployments

LITE-28966: Listing all the requests accross deployments for the account
  • Loading branch information
d3rky authored Jul 19, 2023
2 parents d1d0cab + eaed454 commit 36d1c62
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 38 deletions.
7 changes: 5 additions & 2 deletions connect_ext_ppr/models/deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class DeploymentRequest(Model):
PREFIX = 'DPLR'

id = db.Column(db.String(20), primary_key=True)
deployment = db.Column(db.ForeignKey(Deployment.id))
ppr = db.Column(db.String, db.ForeignKey(PPRVersion.id))
deployment_id = db.Column(db.ForeignKey(Deployment.id))
ppr_id = db.Column(db.String, db.ForeignKey(PPRVersion.id))
status = db.Column(
db.Enum(DeploymentRequestStatusChoices, validate_strings=True),
default=DeploymentRequestStatusChoices.PENDING,
Expand All @@ -58,6 +58,9 @@ class DeploymentRequest(Model):
aborted_at = db.Column(db.DateTime(), nullable=True)
aborted_by = db.Column(db.String(20), nullable=True)

ppr = relationship('PPRVersion', foreign_keys="DeploymentRequest.ppr_id")
deployment = relationship('Deployment', foreign_keys="DeploymentRequest.deployment_id")


class MarketplaceConfiguration(Model):
__tablename__ = 'marketplace_configuration'
Expand Down
33 changes: 25 additions & 8 deletions connect_ext_ppr/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from connect_ext_ppr.models.enums import (
ConfigurationStateChoices,
DeploymentRequestStatusChoices,
DeploymentStatusChoices,
MimeTypeChoices,
PPRStatusChoices,
Expand Down Expand Up @@ -50,14 +51,6 @@ class DeploymentSchema(NonNullSchema):
events: Dict[str, Dict[str, Union[datetime, str]]]


class DeploymentRequestSchema(NonNullSchema):
id: str
deployment: str

class Config:
orm_mode = True


class FileSchema(NonNullSchema):
id: str
name: str
Expand Down Expand Up @@ -97,3 +90,27 @@ class PPRVersionSchema(NonNullSchema):
description: Optional[str] = Field(None, max_length=512)
events: Dict[str, Dict[str, Union[datetime, str]]]
status: PPRStatusChoices


class PPRVersionReferenceSchema(NonNullSchema):
id: str
version: int


class DeploymentReferenceSchema(NonNullSchema):
id: str
product: ProductSchema
hub: HubSchema


class DeploymentRequestSchema(NonNullSchema):
id: str
deployment: DeploymentReferenceSchema
ppr: PPRVersionReferenceSchema
status: DeploymentRequestStatusChoices
manually: bool
delegate_l2: bool
events: Dict[str, Dict[str, Union[datetime, str]]]

class Config:
orm_mode = True
85 changes: 83 additions & 2 deletions connect_ext_ppr/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,37 @@
from connect_ext_ppr.errors import ExtensionHttpError
from connect_ext_ppr.models.configuration import Configuration
from connect_ext_ppr.models.deployment import Deployment
from connect_ext_ppr.schemas import ConfigurationSchema, DeploymentSchema, FileSchema
from connect_ext_ppr.schemas import (
ConfigurationSchema,
DeploymentReferenceSchema,
DeploymentRequestSchema,
DeploymentSchema,
FileSchema,
HubSchema,
PPRVersionReferenceSchema,
ProductSchema,
)


def clean_empties_from_dict(data):
"""
Removes inplace all the fields that are None or empty dicts in data.
Returns param data, that was modified inplace.
If the param is not a dict, will return the param unmodified.
:param data: dict
:rtype: dict
"""
if not isinstance(data, dict):
return data

for key in list(data.keys()):
value = data[key]
if isinstance(value, dict):
clean_empties_from_dict(value)
value = data[key]
if not value:
del data[key]
return data


def _get_extension_client(logger):
Expand All @@ -37,10 +67,15 @@ def get_marketplaces(client, mkp_ids):
return client.marketplaces.filter(rql)


def get_hubs(client, hubs_ids):
rql = R().id.in_(hubs_ids)
return client.hubs.filter(rql)


def get_products(client, prod_ids):
rql = R().visibility.listing.eq(True)
rql |= R().visibility.syndication.eq(True)
rql & R().id.in_(prod_ids)
rql &= R().id.in_(prod_ids)
return client.products.filter(rql)


Expand Down Expand Up @@ -107,6 +142,52 @@ def get_deployment_schema(deployment, product, vendor, hub):
)


def get_deployment_reference_schema(deployment, hub):
product = deployment.product
product_schema = ProductSchema(id=product.id, name=product.name, icon=product.logo)
hub_id = deployment.hub_id
hub_schema = HubSchema(id=hub_id, name=hub['name'])
return DeploymentReferenceSchema(id=deployment.id, product=product_schema, hub=hub_schema)


def get_deployment_request_schema(deployment_request, hub):
"""
Returns DeploymentSchema for the deployment
:param deployment: Deployment model
:param product: Product model from Connect
:param vendor: Vendor Account model from Connect
:param hub: Hub model from Connect
:rtype: DeploymentSchema
"""
ppr = deployment_request.ppr
ppr_schema = PPRVersionReferenceSchema(
id=ppr.id,
version=ppr.version,
)
events = clean_empties_from_dict({
'created': {
'at': deployment_request.created_at,
'by': deployment_request.created_by,
},
'started': {'at': deployment_request.started_at},
'finished': {'at': deployment_request.finished_at},
'aborted': {
'at': deployment_request.aborted_at,
'by': deployment_request.aborted_by,
},
})

return DeploymentRequestSchema(
id=deployment_request.id,
deployment=get_deployment_reference_schema(deployment_request.deployment, hub),
ppr=ppr_schema,
status=deployment_request.status,
manually=deployment_request.manually,
delegate_l2=deployment_request.delegate_l2,
events=events,
)


def get_client_object(client, collection_name, obj_id):
"""
Get client object by id
Expand Down
46 changes: 44 additions & 2 deletions connect_ext_ppr/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from fastapi import Depends, Response, status
from sqlalchemy import exists
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import joinedload

from connect_ext_ppr.db import create_db, get_db, VerboseBaseSession
from connect_ext_ppr.errors import ExtensionHttpError
Expand All @@ -40,7 +41,9 @@
get_configuration_by_id,
get_configuration_schema,
get_deployment_by_id,
get_deployment_request_schema,
get_deployment_schema,
get_hubs,
)


Expand All @@ -56,6 +59,46 @@
)
class ConnectExtensionXvsWebApplication(WebApplicationBase):

@router.get(
'/deployments/requests',
summary='List all request accross deployments',
response_model=List[DeploymentRequestSchema],
)
def list_deployment_requests(
self,
client: ConnectClient = Depends(get_installation_client),
db: VerboseBaseSession = Depends(get_db),
installation: dict = Depends(get_installation),
):
hubs_ids = [
h[0] for h in db.query(Deployment.hub_id).filter_by(
account_id=installation['owner']['id'],
).distinct()
]
hubs = get_hubs(client, hubs_ids)

deployments = db.query(Deployment.id).filter_by(
account_id=installation['owner']['id'],
)

deployment_requests = db.query(DeploymentRequest).options(
joinedload(DeploymentRequest.ppr),
joinedload(DeploymentRequest.deployment),
).filter(
DeploymentRequest.deployment_id.in_(deployments),
)

response_list = []
for dr in deployment_requests:
response_list.append(
get_deployment_request_schema(
dr,
filter_object_list_by_id(hubs, dr.deployment.hub_id),
),
)

return response_list

@router.get(
'/deployments/{deployment_id}',
summary='Deployment details',
Expand Down Expand Up @@ -95,7 +138,6 @@ def get_deployments(
db: VerboseBaseSession = Depends(get_db),
installation: dict = Depends(get_installation),
):

deployments = db.query(Deployment).filter_by(account_id=installation['owner']['id'])
listings = get_all_info(client)
vendors = [li['vendor'] for li in listings]
Expand All @@ -117,7 +159,7 @@ def get_deployments(
)
def add_dep_request(self, db: VerboseBaseSession = Depends(get_db)):
deployment = db.query(Deployment).first()
instance = DeploymentRequest(deployment=deployment.id)
instance = DeploymentRequest(deployment_id=deployment.id)
db.set_next_verbose(instance, 'deployment')
db.commit()
db.refresh(instance)
Expand Down
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ services:
env_file:
- .connect-extension-xvs_dev.env
depends_on:
- db
- cbc_db
- db_ram
links:
- "db_ram:db"

db:
image: postgres:9.6-alpine
Expand Down
58 changes: 43 additions & 15 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#
from contextlib import contextmanager
import json
import random

import pandas as pd
import pytest
Expand All @@ -21,9 +22,10 @@
VerboseBaseSession,
)
from connect_ext_ppr.models.configuration import Configuration
from connect_ext_ppr.models.deployment import Deployment
from connect_ext_ppr.models.deployment import Deployment, DeploymentRequest
from connect_ext_ppr.models.file import File
from connect_ext_ppr.models.replicas import Product
from connect_ext_ppr.models.ppr import PPRVersion
from connect_ext_ppr.webapp import ConnectExtensionXvsWebApplication


Expand Down Expand Up @@ -71,6 +73,23 @@ def mocked_context(config):
)


@pytest.fixture
def product_factory(dbsession):
def _build_product(
id=None,
name='Chat GPT',
logo='/media/VA-000-000/PRD-000-000-000/media/PRD-000-000-000-logo_cLqk6Vm.png',
owner_id='VA-000-000',
):
if not id:
id = 'PR-{0}'.format(random.randint(10000, 99999))
product = Product(id=id, name=name, logo=logo, owner_id=owner_id)
dbsession.add(product)
dbsession.commit()
return product
return _build_product


@pytest.fixture
def deployment(dbsession, product_factory):
product = product_factory()
Expand All @@ -91,38 +110,47 @@ def deployment(dbsession, product_factory):
def deployment_factory(product_factory):
def _build_deployment(
dbsession,
product_id='PRD-XXX-XXX-XXX',
product_id=None,
account_id='PA-000-000',
vendor_id='VA-000-000',
hub_id='HB-0000-0000',
):
product = product_factory(id=product_id, owner_id=vendor_id)
if not product_id:
product = product_factory()
product_id = product.id

dep = Deployment(
product_id=product.id,
product_id=product_id,
account_id=account_id,
vendor_id=vendor_id,
hub_id=hub_id,
)
dbsession.add(product)
dbsession.set_verbose(dep)
dbsession.commit()
return dep
return _build_deployment


@pytest.fixture
def product_factory(dbsession):
def _build_product(
id='PRD-XXX-XXX-XXX',
name='Chat GPT',
logo='/media/VA-000-000/PRD-000-000-000/media/PRD-000-000-000-logo_cLqk6Vm.png',
owner_id='VA-000-000',
def deployment_request_factory(dbsession):
def _build_deployment_request(
deployment=None,
ppr_id='PPRFL-12345',
):
product = Product(id=id, name=name, logo=logo, owner_id=owner_id)
dbsession.add(product)
if not deployment:
deployment = deployment_factory(dbsession, id='DPLR-123-123-123')

ppr = PPRVersion(id=ppr_id, product_version=1)
dep_req = DeploymentRequest(
deployment_id=deployment.id,
ppr_id=ppr_id,
created_by=deployment.account_id,
)
dbsession.add(ppr)
dbsession.set_verbose(dep_req)
dbsession.commit()
return product
return _build_product
return dep_req
return _build_deployment_request


@pytest.fixture
Expand Down
Loading

0 comments on commit 36d1c62

Please sign in to comment.