From e212f4fcb3d6f7d2853c6a80144f193b6cc266bf Mon Sep 17 00:00:00 2001 From: SudhakarReddy Date: Thu, 6 Sep 2018 12:37:26 +0300 Subject: Added V0 Registry API Change-Id: Iac61b136485ddb06b76d8b701ab51e8e18439e94 Issue-ID: MULTICLOUD-354 Signed-off-by: SudhakarReddy --- azure/assembly.xml | 6 +- azure/azure/__init__.py | 0 azure/azure/api_v2/__init__.py | 0 azure/azure/api_v2/api_definition/__init__.py | 0 azure/azure/api_v2/api_definition/hosts.yaml | 72 -- azure/azure/api_v2/api_definition/images.yaml | 76 -- azure/azure/api_v2/api_definition/networks.yaml | 91 --- azure/azure/api_v2/api_definition/ports.yaml | 83 --- azure/azure/api_v2/api_definition/subnets.yaml | 88 --- azure/azure/api_v2/api_definition/utils.py | 31 - azure/azure/api_v2/api_router/__init__.py | 0 azure/azure/api_v2/api_router/root.py | 34 - azure/azure/api_v2/api_router/swagger_json.py | 25 - azure/azure/api_v2/api_router/v0_controller.py | 48 -- azure/azure/api_v2/app.py | 35 - azure/azure/api_v2/service.py | 54 -- azure/azure/event_listener/__init__.py | 0 azure/azure/event_listener/i18n.py | 39 - azure/azure/event_listener/listener.conf | 15 - azure/azure/event_listener/server.py | 126 ---- azure/azure/middleware.py | 59 -- azure/azure/pub/__init__.py | 0 azure/azure/pub/config/__init__.py | 0 azure/azure/pub/config/config.py | 41 -- azure/azure/pub/config/log.yml | 26 - azure/azure/pub/database/__init__.py | 0 azure/azure/pub/database/models.py | 23 - azure/azure/pub/exceptions.py | 66 -- azure/azure/pub/msapi/__init__.py | 0 azure/azure/pub/msapi/extsys.py | 46 -- azure/azure/pub/utils/__init__.py | 0 azure/azure/pub/utils/enumutil.py | 15 - azure/azure/pub/utils/fileutil.py | 50 -- azure/azure/pub/utils/idutil.py | 18 - azure/azure/pub/utils/restcall.py | 782 --------------------- azure/azure/pub/utils/syscomm.py | 111 --- azure/azure/pub/utils/timeutil.py | 17 - azure/azure/pub/utils/values.py | 22 - azure/azure/pub/vim/__init__.py | 0 azure/azure/pub/vim/const.py | 14 - azure/azure/samples/__init__.py | 0 azure/azure/samples/tests.py | 31 - azure/azure/samples/urls.py | 17 - azure/azure/samples/views.py | 35 - azure/azure/scripts/__init__.py | 0 azure/azure/scripts/api.py | 41 -- azure/azure/settings-cover.py | 22 - azure/azure/settings.py | 98 --- azure/azure/swagger/__init__.py | 0 azure/azure/swagger/image_utils.py | 65 -- azure/azure/swagger/tests.py | 31 - azure/azure/swagger/urls.py | 37 - azure/azure/swagger/utils.py | 37 - azure/azure/swagger/views.py | 29 - azure/azure/swagger/views/__init__.py | 0 azure/azure/swagger/views/multivim.swagger.json | 51 -- azure/azure/swagger/views/registry/__init__.py | 0 azure/azure/swagger/views/registry/views.py | 167 ----- azure/azure/swagger/views/swagger_json.py | 42 -- azure/azure/swagger/volume_utils.py | 72 -- azure/azure/tests/__init__.py | 0 azure/azure/tests/test_aai_client.py | 378 ---------- azure/azure/tests/test_restcall.py | 101 --- azure/azure/tests/test_syscomm.py | 37 - azure/azure/urls.py | 18 - azure/azure/wsgi.py | 20 - azure/manage.py | 2 +- azure/multicloud_azure/__init__.py | 0 azure/multicloud_azure/api_v2/__init__.py | 0 .../api_v2/api_definition/__init__.py | 0 .../api_v2/api_definition/hosts.yaml | 72 ++ .../api_v2/api_definition/images.yaml | 76 ++ .../api_v2/api_definition/networks.yaml | 91 +++ .../api_v2/api_definition/ports.yaml | 83 +++ .../api_v2/api_definition/subnets.yaml | 88 +++ .../api_v2/api_definition/utils.py | 31 + .../multicloud_azure/api_v2/api_router/__init__.py | 0 azure/multicloud_azure/api_v2/api_router/root.py | 34 + .../api_v2/api_router/swagger_json.py | 25 + .../api_v2/api_router/v0_controller.py | 48 ++ azure/multicloud_azure/api_v2/app.py | 35 + azure/multicloud_azure/api_v2/service.py | 54 ++ azure/multicloud_azure/event_listener/__init__.py | 0 azure/multicloud_azure/event_listener/i18n.py | 39 + .../multicloud_azure/event_listener/listener.conf | 15 + azure/multicloud_azure/event_listener/server.py | 126 ++++ azure/multicloud_azure/middleware.py | 59 ++ azure/multicloud_azure/pub/__init__.py | 0 azure/multicloud_azure/pub/config/__init__.py | 0 azure/multicloud_azure/pub/config/config.py | 41 ++ azure/multicloud_azure/pub/config/log.yml | 26 + azure/multicloud_azure/pub/database/__init__.py | 0 azure/multicloud_azure/pub/database/models.py | 23 + azure/multicloud_azure/pub/exceptions.py | 66 ++ azure/multicloud_azure/pub/msapi/__init__.py | 0 azure/multicloud_azure/pub/msapi/extsys.py | 47 ++ azure/multicloud_azure/pub/utils/__init__.py | 0 azure/multicloud_azure/pub/utils/enumutil.py | 15 + azure/multicloud_azure/pub/utils/fileutil.py | 50 ++ azure/multicloud_azure/pub/utils/idutil.py | 18 + azure/multicloud_azure/pub/utils/restcall.py | 530 ++++++++++++++ azure/multicloud_azure/pub/utils/syscomm.py | 111 +++ azure/multicloud_azure/pub/utils/timeutil.py | 17 + azure/multicloud_azure/pub/utils/values.py | 22 + azure/multicloud_azure/pub/vim/__init__.py | 0 azure/multicloud_azure/pub/vim/const.py | 14 + azure/multicloud_azure/pub/vim/vimapi/__init__.py | 0 .../multicloud_azure/pub/vim/vimapi/baseclient.py | 42 ++ .../pub/vim/vimapi/compute/OperateCompute.py | 29 + .../pub/vim/vimapi/compute/OperateFlavors.py | 33 + .../pub/vim/vimapi/compute/__init__.py | 0 azure/multicloud_azure/pub/vim/vimsdk/__init__.py | 0 .../pub/vim/vimsdk/azure_credentials.py | 28 + azure/multicloud_azure/pub/vim/vimsdk/sdk.py | 20 + azure/multicloud_azure/samples/__init__.py | 0 azure/multicloud_azure/samples/tests.py | 31 + azure/multicloud_azure/samples/urls.py | 17 + azure/multicloud_azure/samples/views.py | 35 + azure/multicloud_azure/scripts/__init__.py | 0 azure/multicloud_azure/scripts/api.py | 41 ++ azure/multicloud_azure/settings-cover.py | 22 + azure/multicloud_azure/settings.py | 98 +++ azure/multicloud_azure/swagger/__init__.py | 0 azure/multicloud_azure/swagger/compute_utils.py | 29 + azure/multicloud_azure/swagger/image_utils.py | 65 ++ .../swagger/multivim.flavor.swagger.json | 365 ++++++++++ azure/multicloud_azure/swagger/tests.py | 31 + azure/multicloud_azure/swagger/urls.py | 37 + azure/multicloud_azure/swagger/utils.py | 37 + azure/multicloud_azure/swagger/views.py | 29 + azure/multicloud_azure/swagger/views/__init__.py | 0 .../swagger/views/flavor/__init__.py | 0 .../multicloud_azure/swagger/views/flavor/views.py | 98 +++ .../swagger/views/multivim.flavor.swagger.json | 365 ++++++++++ .../swagger/views/multivim.swagger.json | 51 ++ .../swagger/views/registry/__init__.py | 0 .../swagger/views/registry/views.py | 87 +++ .../multicloud_azure/swagger/views/swagger_json.py | 42 ++ azure/multicloud_azure/swagger/volume_utils.py | 72 ++ azure/multicloud_azure/tests/__init__.py | 0 azure/multicloud_azure/tests/test_aai_client.py | 77 ++ azure/multicloud_azure/tests/test_flavor_view.py | 76 ++ azure/multicloud_azure/tests/test_restcall.py | 101 +++ azure/multicloud_azure/tests/test_syscomm.py | 37 + azure/multicloud_azure/urls.py | 18 + azure/multicloud_azure/wsgi.py | 20 + azure/requirements.txt | 6 + azure/run.sh | 4 +- azure/setup.py | 2 +- azure/stop.sh | 2 +- azure/tox.ini | 4 +- sonar.sh | 2 +- 152 files changed, 3906 insertions(+), 3447 deletions(-) delete mode 100644 azure/azure/__init__.py delete mode 100644 azure/azure/api_v2/__init__.py delete mode 100644 azure/azure/api_v2/api_definition/__init__.py delete mode 100644 azure/azure/api_v2/api_definition/hosts.yaml delete mode 100644 azure/azure/api_v2/api_definition/images.yaml delete mode 100644 azure/azure/api_v2/api_definition/networks.yaml delete mode 100644 azure/azure/api_v2/api_definition/ports.yaml delete mode 100644 azure/azure/api_v2/api_definition/subnets.yaml delete mode 100644 azure/azure/api_v2/api_definition/utils.py delete mode 100644 azure/azure/api_v2/api_router/__init__.py delete mode 100644 azure/azure/api_v2/api_router/root.py delete mode 100644 azure/azure/api_v2/api_router/swagger_json.py delete mode 100644 azure/azure/api_v2/api_router/v0_controller.py delete mode 100644 azure/azure/api_v2/app.py delete mode 100644 azure/azure/api_v2/service.py delete mode 100644 azure/azure/event_listener/__init__.py delete mode 100644 azure/azure/event_listener/i18n.py delete mode 100644 azure/azure/event_listener/listener.conf delete mode 100644 azure/azure/event_listener/server.py delete mode 100644 azure/azure/middleware.py delete mode 100644 azure/azure/pub/__init__.py delete mode 100644 azure/azure/pub/config/__init__.py delete mode 100644 azure/azure/pub/config/config.py delete mode 100644 azure/azure/pub/config/log.yml delete mode 100644 azure/azure/pub/database/__init__.py delete mode 100644 azure/azure/pub/database/models.py delete mode 100644 azure/azure/pub/exceptions.py delete mode 100644 azure/azure/pub/msapi/__init__.py delete mode 100644 azure/azure/pub/msapi/extsys.py delete mode 100644 azure/azure/pub/utils/__init__.py delete mode 100644 azure/azure/pub/utils/enumutil.py delete mode 100644 azure/azure/pub/utils/fileutil.py delete mode 100644 azure/azure/pub/utils/idutil.py delete mode 100644 azure/azure/pub/utils/restcall.py delete mode 100644 azure/azure/pub/utils/syscomm.py delete mode 100644 azure/azure/pub/utils/timeutil.py delete mode 100644 azure/azure/pub/utils/values.py delete mode 100644 azure/azure/pub/vim/__init__.py delete mode 100644 azure/azure/pub/vim/const.py delete mode 100644 azure/azure/samples/__init__.py delete mode 100644 azure/azure/samples/tests.py delete mode 100644 azure/azure/samples/urls.py delete mode 100644 azure/azure/samples/views.py delete mode 100644 azure/azure/scripts/__init__.py delete mode 100644 azure/azure/scripts/api.py delete mode 100644 azure/azure/settings-cover.py delete mode 100644 azure/azure/settings.py delete mode 100644 azure/azure/swagger/__init__.py delete mode 100644 azure/azure/swagger/image_utils.py delete mode 100644 azure/azure/swagger/tests.py delete mode 100644 azure/azure/swagger/urls.py delete mode 100644 azure/azure/swagger/utils.py delete mode 100644 azure/azure/swagger/views.py delete mode 100644 azure/azure/swagger/views/__init__.py delete mode 100644 azure/azure/swagger/views/multivim.swagger.json delete mode 100644 azure/azure/swagger/views/registry/__init__.py delete mode 100644 azure/azure/swagger/views/registry/views.py delete mode 100644 azure/azure/swagger/views/swagger_json.py delete mode 100644 azure/azure/swagger/volume_utils.py delete mode 100644 azure/azure/tests/__init__.py delete mode 100644 azure/azure/tests/test_aai_client.py delete mode 100644 azure/azure/tests/test_restcall.py delete mode 100644 azure/azure/tests/test_syscomm.py delete mode 100644 azure/azure/urls.py delete mode 100644 azure/azure/wsgi.py create mode 100644 azure/multicloud_azure/__init__.py create mode 100644 azure/multicloud_azure/api_v2/__init__.py create mode 100644 azure/multicloud_azure/api_v2/api_definition/__init__.py create mode 100644 azure/multicloud_azure/api_v2/api_definition/hosts.yaml create mode 100644 azure/multicloud_azure/api_v2/api_definition/images.yaml create mode 100644 azure/multicloud_azure/api_v2/api_definition/networks.yaml create mode 100644 azure/multicloud_azure/api_v2/api_definition/ports.yaml create mode 100644 azure/multicloud_azure/api_v2/api_definition/subnets.yaml create mode 100644 azure/multicloud_azure/api_v2/api_definition/utils.py create mode 100644 azure/multicloud_azure/api_v2/api_router/__init__.py create mode 100644 azure/multicloud_azure/api_v2/api_router/root.py create mode 100644 azure/multicloud_azure/api_v2/api_router/swagger_json.py create mode 100644 azure/multicloud_azure/api_v2/api_router/v0_controller.py create mode 100644 azure/multicloud_azure/api_v2/app.py create mode 100644 azure/multicloud_azure/api_v2/service.py create mode 100644 azure/multicloud_azure/event_listener/__init__.py create mode 100644 azure/multicloud_azure/event_listener/i18n.py create mode 100644 azure/multicloud_azure/event_listener/listener.conf create mode 100644 azure/multicloud_azure/event_listener/server.py create mode 100644 azure/multicloud_azure/middleware.py create mode 100644 azure/multicloud_azure/pub/__init__.py create mode 100644 azure/multicloud_azure/pub/config/__init__.py create mode 100644 azure/multicloud_azure/pub/config/config.py create mode 100644 azure/multicloud_azure/pub/config/log.yml create mode 100644 azure/multicloud_azure/pub/database/__init__.py create mode 100644 azure/multicloud_azure/pub/database/models.py create mode 100644 azure/multicloud_azure/pub/exceptions.py create mode 100644 azure/multicloud_azure/pub/msapi/__init__.py create mode 100644 azure/multicloud_azure/pub/msapi/extsys.py create mode 100644 azure/multicloud_azure/pub/utils/__init__.py create mode 100644 azure/multicloud_azure/pub/utils/enumutil.py create mode 100644 azure/multicloud_azure/pub/utils/fileutil.py create mode 100644 azure/multicloud_azure/pub/utils/idutil.py create mode 100644 azure/multicloud_azure/pub/utils/restcall.py create mode 100644 azure/multicloud_azure/pub/utils/syscomm.py create mode 100644 azure/multicloud_azure/pub/utils/timeutil.py create mode 100644 azure/multicloud_azure/pub/utils/values.py create mode 100644 azure/multicloud_azure/pub/vim/__init__.py create mode 100644 azure/multicloud_azure/pub/vim/const.py create mode 100644 azure/multicloud_azure/pub/vim/vimapi/__init__.py create mode 100644 azure/multicloud_azure/pub/vim/vimapi/baseclient.py create mode 100644 azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py create mode 100644 azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py create mode 100644 azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py create mode 100644 azure/multicloud_azure/pub/vim/vimsdk/__init__.py create mode 100644 azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py create mode 100644 azure/multicloud_azure/pub/vim/vimsdk/sdk.py create mode 100644 azure/multicloud_azure/samples/__init__.py create mode 100644 azure/multicloud_azure/samples/tests.py create mode 100644 azure/multicloud_azure/samples/urls.py create mode 100644 azure/multicloud_azure/samples/views.py create mode 100644 azure/multicloud_azure/scripts/__init__.py create mode 100644 azure/multicloud_azure/scripts/api.py create mode 100644 azure/multicloud_azure/settings-cover.py create mode 100644 azure/multicloud_azure/settings.py create mode 100644 azure/multicloud_azure/swagger/__init__.py create mode 100644 azure/multicloud_azure/swagger/compute_utils.py create mode 100644 azure/multicloud_azure/swagger/image_utils.py create mode 100644 azure/multicloud_azure/swagger/multivim.flavor.swagger.json create mode 100644 azure/multicloud_azure/swagger/tests.py create mode 100644 azure/multicloud_azure/swagger/urls.py create mode 100644 azure/multicloud_azure/swagger/utils.py create mode 100644 azure/multicloud_azure/swagger/views.py create mode 100644 azure/multicloud_azure/swagger/views/__init__.py create mode 100644 azure/multicloud_azure/swagger/views/flavor/__init__.py create mode 100644 azure/multicloud_azure/swagger/views/flavor/views.py create mode 100644 azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json create mode 100644 azure/multicloud_azure/swagger/views/multivim.swagger.json create mode 100644 azure/multicloud_azure/swagger/views/registry/__init__.py create mode 100644 azure/multicloud_azure/swagger/views/registry/views.py create mode 100644 azure/multicloud_azure/swagger/views/swagger_json.py create mode 100644 azure/multicloud_azure/swagger/volume_utils.py create mode 100644 azure/multicloud_azure/tests/__init__.py create mode 100644 azure/multicloud_azure/tests/test_aai_client.py create mode 100644 azure/multicloud_azure/tests/test_flavor_view.py create mode 100644 azure/multicloud_azure/tests/test_restcall.py create mode 100644 azure/multicloud_azure/tests/test_syscomm.py create mode 100644 azure/multicloud_azure/urls.py create mode 100644 azure/multicloud_azure/wsgi.py diff --git a/azure/assembly.xml b/azure/assembly.xml index 61a4883..48255fd 100644 --- a/azure/assembly.xml +++ b/azure/assembly.xml @@ -20,8 +20,8 @@ - azure - /azure + multicloud_azure + /multicloud_azure **/*.py **/*.json @@ -61,6 +61,6 @@ - azure + multicloud_azure diff --git a/azure/azure/__init__.py b/azure/azure/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/api_v2/__init__.py b/azure/azure/api_v2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/api_v2/api_definition/__init__.py b/azure/azure/api_v2/api_definition/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/api_v2/api_definition/hosts.yaml b/azure/azure/api_v2/api_definition/hosts.yaml deleted file mode 100644 index 88eaa09..0000000 --- a/azure/azure/api_v2/api_definition/hosts.yaml +++ /dev/null @@ -1,72 +0,0 @@ ---- - info: - version: "1.0.0" - title: "Multi Cloud Host" - description: "Definition of Host API" - termsOfService: "http://swagger.io/terms/" - schemes: - - "http" - produces: - - "application/json" - paths: - /{vimid}/{tenantid}/hosts/{hostid}: - parameters: - - type: string - name: vimid - - type: string - format: uuid - name: tenantid - - type: string - name: hostid - in: path - required: true - get: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/host" - get_all: - produces: - - "application/json" - responses: - "200": - schema: - type: "array" - items: - $ref: "#/definitions/host" - vim_path: "/compute/os-hypervisors" - definitions: - host: - plural_vim_resource: "hypervisors" - vim_resource: "hypervisor" - plural: "hosts" - properties: - name: - type: string - required: true - source: hypervisor.hypervisor_hostname - id: - type: string - required: true - source: hypervisor.id - status: - type: string - source: hypervisor.status - state: - type: string - source: hypervisor.state - cpu: - type: integer - minimal: 1 - source: hypervisor.vcpus - action: copy - disk_gb: - type: integer - minimal: 0 - source: hypervisor.local_gb - memory_mb: - type: integer - minimal: 0 - source: hypervisor.memory_mb diff --git a/azure/azure/api_v2/api_definition/images.yaml b/azure/azure/api_v2/api_definition/images.yaml deleted file mode 100644 index 723884c..0000000 --- a/azure/azure/api_v2/api_definition/images.yaml +++ /dev/null @@ -1,76 +0,0 @@ ---- - info: - version: "1.0.0" - title: "Multi Cloud Image" - description: "Definition of Image API" - termsOfService: "http://swagger.io/terms/" - schemes: - - "http" - produces: - - "application/json" - paths: - /{vimid}/{tenantid}/images/{imageid}: - parameters: - - type: string - name: vimid - - type: string - format: uuid - name: tenantid - - type: string - name: imageid - in: path - required: true - get: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/image" - get_all: - produces: - - "application/json" - responses: - "200": - schema: - type: "array" - items: - $ref: "#/definitions/image" - post: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/image" - delete: - responses: "204" - vim_path: "/image/v2/images" - definitions: - image: - plural_vim_resource: "images" - vim_resource: "image" - plural: "images" - properties: - name: - type: string - required: true - source: image.name - id: - type: string - source: image.id - status: - type: string - source: image.status - imageType: - type: string - source: image.disk_format - containerFormat: - type: string - source: image.container_format - visibility: - type: string - source: image.visibility - size: - type: integer - source: image.size \ No newline at end of file diff --git a/azure/azure/api_v2/api_definition/networks.yaml b/azure/azure/api_v2/api_definition/networks.yaml deleted file mode 100644 index c00808f..0000000 --- a/azure/azure/api_v2/api_definition/networks.yaml +++ /dev/null @@ -1,91 +0,0 @@ ---- - info: - version: "1.0.0" - title: "Multi Cloud Network" - description: "Definition of Host API" - termsOfService: "http://swagger.io/terms/" - schemes: - - "http" - produces: - - "application/json" - paths: - /{vimid}/{tenantid}/networks/{networkid}: - parameters: - - type: string - name: vimid - - type: string - format: uuid - name: tenantid - - type: string - name: networkid - in: path - required: true - get: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/network" - get_all: - produces: - - "application/json" - responses: - "200": - schema: - type: "array" - items: - $ref: "#/definitions/network" - post: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/network" - delete: - responses: "204" - vim_path: "/network/v2.0/networks" - definitions: - network: - plural_vim_resource: "networks" - vim_resource: "network" - plural: "networks" - properties: - name: - type: string - required: true - source: network.name - id: - type: string - source: network.id - status: - type: string - source: network.status - segmentationId: - type: string - source: network.provider:segmentation_id - default: None - physicalNetwork: - type: string - source: network.provider:physical_network - default: None - networkType: - type: string - source: network.provider:network_type - default: None - tenantId: - type: string - source: network.tenant_id - shared: - type: boolean - source: network.shared - required: true - routerExternal: - type: boolean - source: network.router:external - required: true - vlanTransparent: - type: boolean - source: network.vlan_transparent - default: false diff --git a/azure/azure/api_v2/api_definition/ports.yaml b/azure/azure/api_v2/api_definition/ports.yaml deleted file mode 100644 index e159593..0000000 --- a/azure/azure/api_v2/api_definition/ports.yaml +++ /dev/null @@ -1,83 +0,0 @@ ---- - info: - version: "1.0.0" - title: "Multi Cloud Port" - description: "Definition of Port API" - termsOfService: "http://swagger.io/terms/" - schemes: - - "http" - produces: - - "application/json" - paths: - /{vimid}/{tenantid}/ports/{portid}: - parameters: - - type: string - name: vimid - - type: string - format: uuid - name: tenantid - - type: string - name: portid - in: path - required: true - get: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/port" - get_all: - produces: - - "application/json" - responses: - "200": - schema: - type: "array" - items: - $ref: "#/definitions/port" - post: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/port" - delete: - responses: "204" - vim_path: "/network/v2.0/ports" - definitions: - port: - plural_vim_resource: "ports" - vim_resource: "port" - plural: "port" - properties: - name: - type: string - required: true - source: port.name - id: - type: string - source: port.id - status: - type: string - source: port.status - networkId: - type: string - source: port.network_id - required: true - vnicType: - source: port.binding:vnic_type - securityGroups: - type: string - source: port.security_groups - tenantId: - type: string - source: port.tenant_id - macAddress: - type: string - source: port.mac_address - subnetId: - source: port.fixed_ips[0].subnet_id - ip: - source: port.fixed_ips[0].ip_address diff --git a/azure/azure/api_v2/api_definition/subnets.yaml b/azure/azure/api_v2/api_definition/subnets.yaml deleted file mode 100644 index e48d570..0000000 --- a/azure/azure/api_v2/api_definition/subnets.yaml +++ /dev/null @@ -1,88 +0,0 @@ ---- - info: - version: "1.0.0" - title: "Multi Cloud Subnet" - description: "Definition of Subnet API" - termsOfService: "http://swagger.io/terms/" - schemes: - - "http" - produces: - - "application/json" - paths: - /{vimid}/{tenantid}/subnets/{subnetid}: - parameters: - - type: string - name: vimid - - type: string - format: uuid - name: tenantid - - type: string - name: subnetid - in: path - required: true - get: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/subnet" - get_all: - produces: - - "application/json" - responses: - "200": - schema: - type: "array" - items: - $ref: "#/definitions/subnet" - post: - produces: - - "application/json" - responses: - "200": - schema: - $ref: "#/definitions/subnet" - delete: - responses: "204" - vim_path: "/network/v2.0/subnets" - definitions: - subnet: - plural_vim_resource: "subnets" - vim_resource: "subnet" - plural: "subnets" - properties: - name: - type: string - required: true - source: subnet.name - id: - type: string - source: subnet.id - status: - type: string - source: subnet.status - networkId: - type: string - source: subnet.network_id - required: true - allocationPools: - source: subnet.allocation_pools - gatewayIp: - type: string - source: subnet.gateway_ip - default: None - tenantId: - type: string - source: subnet.tenant_id - enableDhcp: - type: boolean - source: subnet.enable_dhcp - ipVersion: - source: subnet.ip_version - dnsNameServers: - source: subnet.dns_nameservers - cidr: - source: subnet.cidr - hostRoutes: - source: subnet.host_routes diff --git a/azure/azure/api_v2/api_definition/utils.py b/azure/azure/api_v2/api_definition/utils.py deleted file mode 100644 index 3f5a8a1..0000000 --- a/azure/azure/api_v2/api_definition/utils.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pkg_resources -import yaml - - -def get_definition_list(): - """ Get API Definition from YAML files. """ - - api_def = [] - definition_dir = __name__[:__name__.rfind(".")] - for f in pkg_resources.resource_listdir(definition_dir, '.'): - if f.endswith(".yaml"): - with pkg_resources.resource_stream(definition_dir, f) as fd: - # TODO(xiaohhui): Should add exception handler to inform user - # of potential error. - api_def.append(yaml.safe_load(fd)) - - return api_def diff --git a/azure/azure/api_v2/api_router/__init__.py b/azure/azure/api_v2/api_router/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/api_v2/api_router/root.py b/azure/azure/api_v2/api_router/root.py deleted file mode 100644 index 0b6f995..0000000 --- a/azure/azure/api_v2/api_router/root.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pecan -from pecan import rest - -from azure.api_v2.api_router import v0_controller - - -class AzureController(rest.RestController): - v0 = v0_controller.V0_Controller() - - -class APIController(rest.RestController): - pass - - -# Pecan workaround for the dash in path. -pecan.route(APIController, "multicloud-azure", AzureController()) - - -class RootController(object): - api = APIController() diff --git a/azure/azure/api_v2/api_router/swagger_json.py b/azure/azure/api_v2/api_router/swagger_json.py deleted file mode 100644 index 8573a46..0000000 --- a/azure/azure/api_v2/api_router/swagger_json.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pecan -from pecan import rest - -from azure.swagger import utils - - -class SwaggerJson(rest.RestController): - - @pecan.expose("json") - def get(self): - return utils.get_swagger_json_data() diff --git a/azure/azure/api_v2/api_router/v0_controller.py b/azure/azure/api_v2/api_router/v0_controller.py deleted file mode 100644 index 68aac1b..0000000 --- a/azure/azure/api_v2/api_router/v0_controller.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pecan -from pecan import rest - -from azure.api_v2.api_router import swagger_json - - -class V0_Controller(rest.RestController): - - def get(self, vim_id, tenant_id): - """ Placeholder for sub controllers. """ - pecan.abort(405) - - def put(self, vim_id, tenant_id): - """ Placeholder for sub controllers. """ - pecan.abort(405) - - def post(self, vim_id, tenant_id): - """ Placeholder for sub controllers. """ - pecan.abort(405) - - def delete(self, vim_id, tenant_id): - """ Placeholder for sub controllers. """ - pecan.abort(405) - - def get_all(self, vim_id, tenant_id): - """ Placeholder for sub controllers. """ - pecan.abort(405) - - -pecan.route(V0_Controller, "swagger.json", swagger_json.SwaggerJson()) - - -# Insert API stem from yaml files. -# controller_builder.insert_dynamic_controller(V0_Controller) diff --git a/azure/azure/api_v2/app.py b/azure/azure/api_v2/app.py deleted file mode 100644 index 2c13403..0000000 --- a/azure/azure/api_v2/app.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pecan - - -def setup_app(config=None): - app_conf = { - 'root': "azure.api_v2.api_router.root.RootController", - 'modules': ["azure.api_v2"], - 'debug': True, - # NOTE: By default, guess_content_type_from_ext is True, and Pecan will - # strip the file extension from url. For example, ../../swagger.json - # will look like ../../swagger to Pecan API router. This makes other - # url like ../../swagger.txt get the same API route. Set this to False - # to do strict url mapping. - 'guess_content_type_from_ext': False - } - app = pecan.make_app( - app_conf.pop('root'), - **app_conf - ) - - return app diff --git a/azure/azure/api_v2/service.py b/azure/azure/api_v2/service.py deleted file mode 100644 index 2b73c15..0000000 --- a/azure/azure/api_v2/service.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_concurrency import processutils -from oslo_config import cfg -from oslo_service import service -from oslo_service import wsgi - -from azure.api_v2 import app -from azure.pub.config import config as mc_cfg - - -CONF = cfg.CONF - - -class WSGIService(service.ServiceBase): - """Provides ability to launch API from wsgi app.""" - - def __init__(self): - self.app = app.setup_app() - - self.workers = processutils.get_worker_count() - - self.server = wsgi.Server( - CONF, - "azure", - self.app, - host="0.0.0.0", - port=mc_cfg.API_SERVER_PORT, - use_ssl=False - ) - - def start(self): - self.server.start() - - def stop(self): - self.server.stop() - - def wait(self): - self.server.wait() - - def reset(self): - self.server.reset() diff --git a/azure/azure/event_listener/__init__.py b/azure/azure/event_listener/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/event_listener/i18n.py b/azure/azure/event_listener/i18n.py deleted file mode 100644 index 8fd9a6e..0000000 --- a/azure/azure/event_listener/i18n.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import oslo_i18n - -DOMAIN = "test_oslo" - -_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# The contextual translation function using the name "_C" -_C = _translators.contextual_form - -# The plural translation function using the name "_P" -_P = _translators.plural_form - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/azure/azure/event_listener/listener.conf b/azure/azure/event_listener/listener.conf deleted file mode 100644 index 4376fe7..0000000 --- a/azure/azure/event_listener/listener.conf +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -[Listener] -rabbit_ip=10.154.9.172 -rabbit_passwd=6C2B96AsbinmFf1a9c6a \ No newline at end of file diff --git a/azure/azure/event_listener/server.py b/azure/azure/event_listener/server.py deleted file mode 100644 index 7f1f830..0000000 --- a/azure/azure/event_listener/server.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from oslo_config import cfg -from oslo_log import log as logging -from i18n import _LI -import oslo_messaging -import ConfigParser -import json -import os -import requests -from azure.pub.config.config import MR_ADDR -from azure.pub.config.config import MR_PORT - - -LOG = logging.getLogger(__name__) - - -def prepare(): - - product_name = "oslo_server" - logging.register_options(cfg.CONF) - logging.setup(cfg.CONF, product_name) - - -''' -below items must be added into vio nova.conf then restart nova services: -notification_driver=messaging -notification_topics= notifications_test -notify_on_state_change=vm_and_task_state -notify_on_any_change=True -instance_usage_audit=True -instance_usage_audit_period=hour -''' - - -def getConfig(section, key): - - config = ConfigParser.ConfigParser() - path = os.path.split(os.path.realpath(__file__))[0] + '/listener.conf' - config.read(path) - return config.get(section, key) - - -class NotificationEndPoint(): - - filter_rule = oslo_messaging.NotificationFilter( - publisher_id='^compute.*') - - def info(self, ctxt, publisher_id, event_type, payload, metadata): - - VM_EVENTS = { - 'compute.instance.unpause.start', - 'compute.instance.pause.start', - 'compute.instance.power_off.start', - 'compute.instance.reboot.start', - 'compute.instance.create.start' - } - - status = payload.get('state_description') - if status != '' and event_type in VM_EVENTS: - url = 'http://%s:%s/events/test' % (MR_ADDR, MR_PORT) - headers = {'Content-type': 'application/json'} - requests.post(url, json.dumps(payload), headers=headers) - - LOG.info(event_type) - self.action(payload) - - def action(self, data): - LOG.info(_LI(json.dumps(data))) - - -class Server(object): - - def __init__(self): - self.topic = 'notifications_test' - self.server = None - prepare() - - -class NotificationServer(Server): - - def __init__(self): - super(NotificationServer, self).__init__() - # rabbit IP and password come from listener.conf - url = 'rabbit://test:%s@%s:5672/' % ( - getConfig('Listener', 'rabbit_passwd'), - getConfig('Listener', 'rabbit_ip') - ) - self.transport = oslo_messaging.get_notification_transport( - cfg.CONF, - url=url) - # The exchange must be the same as - # control_exchange in transport setting in client. - self.targets = [oslo_messaging.Target( - topic=self.topic, - exchange='nova')] - self.endpoints = [NotificationEndPoint()] - - def start(self): - LOG.info(_LI("Start Notification server...")) - self.server = oslo_messaging.get_notification_listener( - self.transport, - self.targets, - self.endpoints, - executor='threading') - self.server.start() - self.server.wait() - - -if __name__ == '__main__': - - notification_server = NotificationServer() - notification_server.start() diff --git a/azure/azure/middleware.py b/azure/azure/middleware.py deleted file mode 100644 index 1edc44b..0000000 --- a/azure/azure/middleware.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -import uuid -from onaplogging.mdcContext import MDC -from azure.pub.config.config import SERVICE_NAME -from azure.pub.config.config import FORWARDED_FOR_FIELDS - - -class LogContextMiddleware(object): - - # the last IP behind multiple proxies, if no exist proxies - # get local host ip. - def _getLastIp(self, request): - - ip = "" - try: - for field in FORWARDED_FOR_FIELDS: - if field in request.META: - if ',' in request.META[field]: - parts = request.META[field].split(',') - ip = parts[-1].strip().split(":")[0] - else: - ip = request.META[field].split(":")[0] - - if ip == "": - ip = request.META.get("HTTP_HOST").split(":")[0] - - except Exception: - pass - - return ip - - def process_request(self, request): - - ReqeustID = request.META.get("HTTP_X_TRANSACTIONID", None) - if ReqeustID is None: - ReqeustID = str(uuid.uuid3(uuid.NAMESPACE_URL, SERVICE_NAME)) - MDC.put("requestID", ReqeustID) - InovocationID = str(uuid.uuid4()) - MDC.put("invocationID", InovocationID) - MDC.put("serviceName", SERVICE_NAME) - MDC.put("serviceIP", self._getLastIp(request)) - return None - - def process_response(self, request, response): - - MDC.clear() - return response diff --git a/azure/azure/pub/__init__.py b/azure/azure/pub/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/config/__init__.py b/azure/azure/pub/config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/config/config.py b/azure/azure/pub/config/config.py deleted file mode 100644 index db09fd6..0000000 --- a/azure/azure/pub/config/config.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import os - -# [MSB] -MSB_SERVICE_IP = "msb.onap.org" -MSB_SERVICE_PORT = "10080" - -# [IMAGE LOCAL PATH] -ROOT_PATH = os.path.dirname(os.path.dirname( - os.path.dirname(os.path.abspath(__file__)))) - -# [A&AI] -AAI_ADDR = "aai.api.simpledemo.openecomp.org" -AAI_PORT = "8443" -AAI_SERVICE_URL = 'https://%s:%s/aai' % (AAI_ADDR, AAI_PORT) -AAI_SCHEMA_VERSION = "v13" -AAI_USERNAME = "AAI" -AAI_PASSWORD = "AAI" - -# [DMaaP] -MR_ADDR = "" -MR_PORT = "" - -# [MDC] -SERVICE_NAME = "multicloud-azure" -FORWARDED_FOR_FIELDS = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST", - "HTTP_X_FORWARDED_SERVER"] - -# [Local Config] -API_SERVER_PORT = 9004 diff --git a/azure/azure/pub/config/log.yml b/azure/azure/pub/config/log.yml deleted file mode 100644 index 7bbc427..0000000 --- a/azure/azure/pub/config/log.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: 1 -disable_existing_loggers: False - -loggers: - azure: - handlers: [azure_handler] - level: "DEBUG" - propagate: False -handlers: - azure_handler: - level: "DEBUG" - class: "logging.handlers.RotatingFileHandler" - filename: "/var/log/onap/multicloud/azure/azure.log" - formatter: "mdcFormat" - maxBytes: 52428800 - backupCount: 10 -formatters: - standard: - format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s" - mdcFormat: - format: "%(asctime)s|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s \t" - mdcfmt: "{requestID} {invocationID} {serviceName} {serviceIP}" - datefmt: "%Y-%m-%d %H:%M:%S" - (): onaplogging.mdcformatter.MDCFormatter - - diff --git a/azure/azure/pub/database/__init__.py b/azure/azure/pub/database/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/database/models.py b/azure/azure/pub/database/models.py deleted file mode 100644 index 757430b..0000000 --- a/azure/azure/pub/database/models.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from django.db import models - - -class VimInstModel(models.Model): - class Meta: - db_table = 'vim_inst_type_mapping' - - vimid = models.CharField( - db_column='VIMID', primary_key=True, max_length=200) - vimtype = models.CharField(db_column="VIMTYPE", max_length=200) - viminst_url = models.CharField(db_column="VIMINSTURL", max_length=200) diff --git a/azure/azure/pub/exceptions.py b/azure/azure/pub/exceptions.py deleted file mode 100644 index 3f38f2c..0000000 --- a/azure/azure/pub/exceptions.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -class ClientException(Exception): - - message = "ClientException" - - def __init__(self, message=None): - self.message = message or self.message - super(ClientException, self).__init__(self.message) - - -class ServerException(Exception): - - message = "ServerException" - - def __init__(self, message=None, status_code="", content=""): - super(ServerException, self).__init__(message) - self.message = message or self.message - self.status_code = status_code - self.content = content - - -class RetriableConnectionFailure(Exception): - pass - - -class ConnectionError(ClientException): - message = "Cannot connect to API service." - - -class ConnectTimeout(ConnectionError, RetriableConnectionFailure): - message = "Timed out connecting to service." - - -class ConnectFailure(ConnectionError, RetriableConnectionFailure): - message = "Connection failure that may be retried." - - -class SSLError(ConnectionError): - message = "An SSL error occurred." - - -class UnknownConnectionError(ConnectionError): - - def __init__(self, msg, original): - super(UnknownConnectionError, self).__init__(msg) - self.original = original - - -class NotFoundError(ServerException): - message = "Cannot find value" - - -class VimDriverAzureException(ServerException): - message = "Cannot find vim driver" diff --git a/azure/azure/pub/msapi/__init__.py b/azure/azure/pub/msapi/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/msapi/extsys.py b/azure/azure/pub/msapi/extsys.py deleted file mode 100644 index f0b9dcc..0000000 --- a/azure/azure/pub/msapi/extsys.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import logging - -from azure.pub.utils.restcall import AAIClient - -logger = logging.getLogger(__name__) - - -def split_vim_to_owner_region(vim_id): - split_vim = vim_id.split('_') - cloud_owner = split_vim[0] - cloud_region = "".join(split_vim[1:]) - return cloud_owner, cloud_region - - -def get_vim_by_id(vim_id): - cloud_owner, cloud_region = split_vim_to_owner_region(vim_id) - client = AAIClient(cloud_owner, cloud_region) - ret = client.get_vim(get_all=True) - esrInfo = ret['esr-system-info-list']['esr-system-info'][0] - data = { - 'type': ret['cloud-type'], - 'version': ret['cloud-region-version'], - 'vimId': vim_id, - 'name': vim_id, - 'userName': esrInfo['user-name'], - 'password': esrInfo['password'], - 'tenant': esrInfo['default-tenant'], - 'url': esrInfo['service-url'], - 'domain': esrInfo['cloud-domain'], - 'cacert': esrInfo.get('ssl-cacert', ""), - 'insecure': esrInfo.get('ssl-insecure', False) - } - ret.update(data) - return ret diff --git a/azure/azure/pub/utils/__init__.py b/azure/azure/pub/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/utils/enumutil.py b/azure/azure/pub/utils/enumutil.py deleted file mode 100644 index eb7a22c..0000000 --- a/azure/azure/pub/utils/enumutil.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -def enum(**enums): - return type('Enum', (), enums) diff --git a/azure/azure/pub/utils/fileutil.py b/azure/azure/pub/utils/fileutil.py deleted file mode 100644 index 1868300..0000000 --- a/azure/azure/pub/utils/fileutil.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -import os -import shutil -import logging -import traceback -import urllib2 - -logger = logging.getLogger(__name__) - - -def make_dirs(path): - if not os.path.exists(path): - os.makedirs(path, 0777) - - -def delete_dirs(path): - try: - if os.path.exists(path): - shutil.rmtree(path) - except Exception as e: - logger.error(traceback.format_exc()) - logger.error("Failed to delete %s:%s", path, e.message) - - -def download_file_from_http(url, local_dir, file_name): - local_file_name = os.path.join(local_dir, file_name) - is_download_ok = False - try: - make_dirs(local_dir) - r = urllib2.Request(url) - req = urllib2.urlopen(r) - save_file = open(local_file_name, 'wb') - save_file.write(req.read()) - save_file.close() - req.close() - is_download_ok = True - except Exception: - logger.error(traceback.format_exc()) - logger.error("Failed to download %s to %s.", url, local_file_name) - return is_download_ok, local_file_name diff --git a/azure/azure/pub/utils/idutil.py b/azure/azure/pub/utils/idutil.py deleted file mode 100644 index be6e8a0..0000000 --- a/azure/azure/pub/utils/idutil.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -from redisco import containers as cont - - -def get_auto_id(id_type, id_group="auto_id_hash"): - auto_id_hash = cont.Hash(id_group) - auto_id_hash.hincrby(id_type, 1) - return auto_id_hash.hget(id_type) diff --git a/azure/azure/pub/utils/restcall.py b/azure/azure/pub/utils/restcall.py deleted file mode 100644 index 4b28098..0000000 --- a/azure/azure/pub/utils/restcall.py +++ /dev/null @@ -1,782 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import sys -import traceback -import logging -import urllib2 -import uuid -import httplib2 -import json - -from azure.pub.config.config import AAI_SCHEMA_VERSION -from azure.pub.config.config import AAI_SERVICE_URL -from azure.pub.config.config import AAI_USERNAME -from azure.pub.config.config import AAI_PASSWORD -from azure.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT - -from azure.pub.exceptions import VimDriverAzureException - -rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2 -HTTP_200_OK, HTTP_201_CREATED = '200', '201' -HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED = '204', '202' -status_ok_list = [HTTP_200_OK, HTTP_201_CREATED, - HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED] -HTTP_404_NOTFOUND, HTTP_403_FORBIDDEN = '404', '403' -HTTP_401_UNAUTHORIZED, HTTP_400_BADREQUEST = '401', '400' - -logger = logging.getLogger(__name__) - - -def call_req(base_url, user, passwd, auth_type, resource, method, content='', - headers=None): - callid = str(uuid.uuid1()) -# logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % ( -# callid, base_url, user, passwd, auth_type, resource, method, content)) - ret = None - resp_status = '' - resp = "" - full_url = "" - - try: - full_url = combine_url(base_url, resource) - if headers is None: - headers = {} - headers['content-type'] = 'application/json' - - if user: - headers['Authorization'] = 'Basic ' + \ - ('%s:%s' % (user, passwd)).encode("base64") - ca_certs = None - for retry_times in range(3): - http = httplib2.Http( - ca_certs=ca_certs, - disable_ssl_certificate_validation=( - auth_type == rest_no_auth)) - http.follow_all_redirects = True - try: - logger.debug("request=%s" % full_url) - resp, resp_content = http.request( - full_url, method=method.upper(), body=content, - headers=headers) - resp_status = resp['status'] - resp_body = resp_content.decode('UTF-8') - - if resp_status in status_ok_list: - ret = [0, resp_body, resp_status, resp] - else: - ret = [1, resp_body, resp_status, resp] - break - except Exception as ex: - if 'httplib.ResponseNotReady' in str(sys.exc_info()): - logger.error(traceback.format_exc()) - ret = [1, "Unable to connect to %s" % full_url, - resp_status, resp] - continue - raise ex - except urllib2.URLError as err: - ret = [2, str(err), resp_status, resp] - except Exception as ex: - logger.error(traceback.format_exc()) - logger.error("[%s]ret=%s" % (callid, str(sys.exc_info()))) - res_info = str(sys.exc_info()) - if 'httplib.ResponseNotReady' in res_info: - res_info = ("The URL[%s] request failed or is not responding." % - full_url) - ret = [3, res_info, resp_status, resp] -# logger.debug("[%s]ret=%s" % (callid, str(ret))) - return ret - - -def req_by_msb(resource, method, content=''): - base_url = "http://%s:%s/" % (MSB_SERVICE_IP, MSB_SERVICE_PORT) - return call_req(base_url, "", "", rest_no_auth, resource, method, content) - - -def combine_url(base_url, resource): - full_url = None - if base_url.endswith('/') and resource.startswith('/'): - full_url = base_url[:-1] + resource - elif base_url.endswith('/') and not resource.startswith('/'): - full_url = base_url + resource - elif not base_url.endswith('/') and resource.startswith('/'): - full_url = base_url + resource - else: - full_url = base_url + '/' + resource - return full_url - - -def get_res_from_aai(resource, content=''): - headers = { - 'X-FromAppId': 'MultiCloud', - 'X-TransactionId': '9001', - 'content-type': 'application/json', - 'accept': 'application/json' - } - base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) - return call_req(base_url, AAI_USERNAME, AAI_PASSWORD, rest_no_auth, - resource, "GET", content, headers) - - -class AAIClient(object): - def __init__(self, cloud_owner, cloud_region): - self.base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) - self.username = AAI_USERNAME - self.password = AAI_PASSWORD - self.default_headers = { - 'X-FromAppId': 'multicloud-openstack-vmware', - 'X-TransactionId': '9004', - 'content-type': 'application/json', - 'accept': 'application/json' - } - self.cloud_owner = cloud_owner - self.cloud_region = cloud_region - self._vim_info = None - - def get_vim(self, get_all=False): - resource = ("/cloud-infrastructure/cloud-regions/cloud-region" - "/%s/%s" % (self.cloud_owner, self.cloud_region)) - if get_all: - resource = "%s?depth=all" % resource - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "GET", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=404, - content="Failed to query VIM with id (%s_%s) from extsys." % ( - self.cloud_owner, self.cloud_region)) - return json.loads(resp[1]) - - def delete_vim(self): - resp = self.get_vim(get_all=True) - logger.debug('Delete tenants') - self._del_tenants(resp) - logger.debug('Delete images') - self._del_images(resp) - logger.debug('Delete flavors') - self._del_flavors(resp) - logger.debug('Delete networks') - self._del_networks(resp) - logger.debug('Delete availability zones') - self._del_azs(resp) - logger.debug('Delete cloud region') - resource = ("/cloud-infrastructure/cloud-regions/cloud-region" - "/%s/%s?resource-version=%s" % - (self.cloud_owner, self.cloud_region, - resp['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete cloud %s_%s: %s." % ( - self.cloud_owner, self.cloud_region, resp[1])) - - def update_vim(self, content): - # update identity url - self.update_identity_url() - # update tenants - self.add_tenants(content) - # update flavors - self.add_images(content) - # update images - self.add_flavors(content) - # update networks - self.add_networks(content) - # update pservers - self.add_pservers(content) - - def update_identity_url(self): - vim = self.get_vim() - vim['identity-url'] = ("http://%s/api/multicloud/v0/%s_%s/identity/" - "v3" % (MSB_SERVICE_IP, self.cloud_owner, - self.cloud_region)) - resource = ("/cloud-infrastructure/cloud-regions/cloud-region" - "/%s/%s" % (self.cloud_owner, self.cloud_region)) - logger.debug("Updating identity url %s" % vim) - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(vim), - headers=self.default_headers) - - def add_tenants(self, content): - for tenant in content['tenants']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/tenants/tenant/%s" % ( - self.cloud_owner, self.cloud_region, tenant['id'])) - body = {'tenant-name': tenant['name']} - logger.debug("Adding tenants to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_flavors(self, content): - for flavor in content['flavors']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/flavors/flavor/%s" % ( - self.cloud_owner, self.cloud_region, flavor['id'])) - body = { - 'flavor-name': flavor['name'], - 'flavor-vcpus': flavor['vcpus'], - 'flavor-ram': flavor['ram'], - 'flavor-disk': flavor['disk'], - 'flavor-ephemeral': flavor['ephemeral'], - 'flavor-swap': flavor['swap'], - 'flavor-is-public': flavor['is_public'], - 'flavor-selflink': flavor['links'][0]['href'], - 'flavor-disabled': flavor['is_disabled'] - } - # Handle extra specs - if flavor['name'].startswith("onap."): - hpa_capabilities = self._get_hpa_capabilities( - flavor) - body['hpa-capabilities'] = { - 'hpa-capability': hpa_capabilities} - - logger.debug("Adding flavors to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_images(self, content): - for image in content['images']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/images/image/%s" % ( - self.cloud_owner, self.cloud_region, image['id'])) - split_image_name = image['name'].split("-") - os_distro = split_image_name[0] - os_version = split_image_name[1] if \ - len(split_image_name) > 1 else "" - body = { - 'image-name': image['name'], - # 'image-architecture': image[''], - 'image-os-distro': os_distro, - 'image-os-version': os_version, - # 'application': image[''], - # 'application-vendor': image[''], - # 'application-version': image[''], - # TODO replace this with image proxy endpoint - 'image-selflink': "", - } - logger.debug("Adding images to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_networks(self, content): - for network in content['networks']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/oam-networks/oam-network/%s" % ( - self.cloud_owner, self.cloud_region, - network['id'])) - body = { - 'network-uuid': network['id'], - 'network-name': network['name'], - 'cvlan-tag': network['segmentationId'] or 0, - } - logger.debug("Adding networks to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_pservers(self, content): - for hypervisor in content['hypervisors']: - resource = ("/cloud-infrastructure/pservers/pserver/%s" % ( - hypervisor['name'])) - body = { - # 'ptnii-equip-name' - 'number-of-cpus': hypervisor['vcpus'], - 'disk-in-gigabytes': hypervisor['local_disk_size'], - 'ram-in-megabytes': hypervisor['memory_size'], - # 'equip-type' - # 'equip-vendor' - # 'equip-model' - # 'fqdn' - # 'pserver-selflink' - 'ipv4-oam-address': hypervisor['host_ip'], - # 'serial-number' - # 'ipaddress-v4-loopback-0' - # 'ipaddress-v6-loopback-0' - # 'ipaddress-v4-aim' - # 'ipaddress-v6-aim' - # 'ipaddress-v6-oam' - # 'inv-status' - 'pserver-id': hypervisor['id'], - # 'internet-topology' - } - logger.debug("Adding pservers") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - # update relationship - resource = ("/cloud-infrastructure/pservers/pserver/%s/" - "relationship-list/relationship" % - hypervisor['name']) - related_link = ("%s/cloud-infrastructure/cloud-regions/" - "cloud-region/%s/%s" % ( - self.base_url, self.cloud_owner, - self.cloud_region)) - body = { - 'related-to': 'cloud-region', - 'related-link': related_link, - 'relationship-data': [ - { - 'relationship-key': 'cloud-region.cloud-owner', - 'relationship-value': self.cloud_owner - }, - { - 'relationship-key': 'cloud-region.cloud-region-id', - 'relationship-value': self.cloud_region - } - ] - } - logger.debug("Connecting pservers and cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def _del_tenants(self, rsp): - tenants = rsp.get("tenants", []) - if not tenants: - return - for tenant in tenants["tenant"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/tenants/tenant/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - tenant['tenant-id'], tenant['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete tenant %s: %s." % ( - tenant['tenant-id'], resp[1])) - - def _del_hpa(self, flavor): - hpas = flavor.get("hpa-capabilities", {}).get("hpa-capability", []) - for hpa in hpas: - resource = ( - "/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/flavors/flavor/%s/hpa-capabilities/hpa-capability/%s" - "?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - flavor['flavor-id'], hpa['hpa-capability-id'], - hpa['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete flavor %s on hpa %s: %s." % ( - flavor['flavor-id'], hpa['hpa-capability-id'], - resp[1])) - - def _del_flavors(self, rsp): - flavors = rsp.get("flavors", []) - if not flavors: - return - for flavor in flavors["flavor"]: - self._del_hpa(flavor) - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/flavors/flavor/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - flavor['flavor-id'], flavor['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete flavor %s: %s." % ( - flavor['flavor-id'], resp[1])) - - def _del_images(self, rsp): - tenants = rsp.get("images", []) - if not tenants: - return - for tenant in tenants["image"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/images/image/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - tenant['image-id'], tenant['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete image %s: %s." % ( - tenant['image-id'], resp[1])) - - def _del_networks(self, rsp): - networks = rsp.get("oam-networks", []) - if not networks: - return - for network in networks["oam-network"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/oam-networks/oam-network/%s?" - "resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - network['network-uuid'], - network['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete network %s: %s." % ( - network['network-uuid'], resp[1])) - - def _del_azs(self, rsp): - azs = rsp.get("availability-zones", []) - if not azs: - return - for az in azs["availability-zone"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/availability-zones/availability-zone/%s?" - "resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - az['availability-zone-name'], - az['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete availability zone %s: %s." % ( - az['availability-zone-name'], resp[1])) - - def _get_hpa_capabilities(self, flavor): - hpa_caps = [] - - # Basic capabilties - caps_dict = self._get_hpa_basic_capabilities(flavor) - if len(caps_dict) > 0: - logger.debug("basic_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # cpupining capabilities - caps_dict = self._get_cpupinning_capabilities(flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("cpupining_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # cputopology capabilities - caps_dict = self._get_cputopology_capabilities(flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("cputopology_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # hugepages capabilities - caps_dict = self._get_hugepages_capabilities(flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("hugepages_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # numa capabilities - caps_dict = self._get_numa_capabilities(flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("numa_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # storage capabilities - caps_dict = self._get_storage_capabilities(flavor) - if len(caps_dict) > 0: - logger.debug("storage_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # CPU instruction set extension capabilities - caps_dict = self._get_instruction_set_capabilities( - flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("instruction_set_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # PCI passthrough capabilities - caps_dict = self._get_pci_passthrough_capabilities( - flavor['extra_specs']) - if len(caps_dict) > 0: - logger.debug("pci_passthrough_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - # ovsdpdk capabilities - caps_dict = self._get_ovsdpdk_capabilities() - if len(caps_dict) > 0: - logger.debug("ovsdpdk_capabilities_info: %s" % caps_dict) - hpa_caps.append(caps_dict) - - return hpa_caps - - def _get_hpa_basic_capabilities(self, flavor): - basic_capability = {} - feature_uuid = uuid.uuid4() - - basic_capability['hpa-capability-id'] = str(feature_uuid) - basic_capability['hpa-feature'] = 'basicCapabilities' - basic_capability['architecture'] = 'generic' - basic_capability['hpa-version'] = 'v1' - - basic_capability['hpa-feature-attributes'] = [] - basic_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'numVirtualCpu', - 'hpa-attribute-value': json.dumps( - {'value': str(flavor['vcpus'])})}) - basic_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'virtualMemSize', - 'hpa-attribute-value': json.dumps({'value': str( - flavor['ram']), 'unit': 'MB'})}) - - return basic_capability - - def _get_cpupinning_capabilities(self, extra_specs): - cpupining_capability = {} - feature_uuid = uuid.uuid4() - - if (extra_specs.get('hw:cpu_policy') or - extra_specs.get('hw:cpu_thread_policy')): - cpupining_capability['hpa-capability-id'] = str(feature_uuid) - cpupining_capability['hpa-feature'] = 'cpuPinning' - cpupining_capability['architecture'] = 'generic' - cpupining_capability['hpa-version'] = 'v1' - - cpupining_capability['hpa-feature-attributes'] = [] - if extra_specs.get('hw:cpu_thread_policy'): - cpupining_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'logicalCpuThreadPinningPolicy', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:cpu_thread_policy'])})}) - if extra_specs.get('hw:cpu_policy'): - cpupining_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'logicalCpuPinningPolicy', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:cpu_policy'])})}) - - return cpupining_capability - - def _get_cputopology_capabilities(self, extra_specs): - cputopology_capability = {} - feature_uuid = uuid.uuid4() - - if (extra_specs.get('hw:cpu_sockets') or - extra_specs.get('hw:cpu_cores') or - extra_specs.get('hw:cpu_threads')): - cputopology_capability['hpa-capability-id'] = str(feature_uuid) - cputopology_capability['hpa-feature'] = 'cpuTopology' - cputopology_capability['architecture'] = 'generic' - cputopology_capability['hpa-version'] = 'v1' - - cputopology_capability['hpa-feature-attributes'] = [] - if extra_specs.get('hw:cpu_sockets'): - cputopology_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'numCpuSockets', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:cpu_sockets'])})}) - if extra_specs.get('hw:cpu_cores'): - cputopology_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'numCpuCores', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:cpu_cores'])})}) - if extra_specs.get('hw:cpu_threads'): - cputopology_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'numCpuThreads', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:cpu_threads'])})}) - - return cputopology_capability - - def _get_hugepages_capabilities(self, extra_specs): - hugepages_capability = {} - feature_uuid = uuid.uuid4() - - if extra_specs.get('hw:mem_page_size'): - hugepages_capability['hpa-capability-id'] = str(feature_uuid) - hugepages_capability['hpa-feature'] = 'hugePages' - hugepages_capability['architecture'] = 'generic' - hugepages_capability['hpa-version'] = 'v1' - - hugepages_capability['hpa-feature-attributes'] = [] - if extra_specs['hw:mem_page_size'] == 'large': - hugepages_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'memoryPageSize', - 'hpa-attribute-value': json.dumps( - {'value': '2', 'unit': 'MB'})}) - elif extra_specs['hw:mem_page_size'] == 'small': - hugepages_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'memoryPageSize', - 'hpa-attribute-value': json.dumps( - {'value': '4', 'unit': 'KB'})}) - elif extra_specs['hw:mem_page_size'] == 'any': - logger.info("Currently HPA feature memoryPageSize " - "did not support 'any' page!!") - else: - hugepages_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'memoryPageSize', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:mem_page_size']), 'unit': 'KB'}) - }) - - return hugepages_capability - - def _get_numa_capabilities(self, extra_specs): - numa_capability = {} - feature_uuid = uuid.uuid4() - - if extra_specs.get('hw:numa_nodes'): - numa_capability['hpa-capability-id'] = str(feature_uuid) - numa_capability['hpa-feature'] = 'numa' - numa_capability['architecture'] = 'generic' - numa_capability['hpa-version'] = 'v1' - - numa_capability['hpa-feature-attributes'] = [] - numa_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'numaNodes', - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs['hw:numa_nodes'])}) - }) - - for num in range(0, int(extra_specs['hw:numa_nodes'])): - numa_cpu_node = "hw:numa_cpus.%s" % num - numa_mem_node = "hw:numa_mem.%s" % num - numacpu_key = "numaCpu-%s" % num - numamem_key = "numaMem-%s" % num - - if (extra_specs.get(numa_cpu_node) and - extra_specs.get(numa_mem_node)): - numa_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': numacpu_key, - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs[numa_cpu_node])}) - }) - numa_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': numamem_key, - 'hpa-attribute-value': json.dumps({'value': str( - extra_specs[numa_mem_node]), 'unit': 'MB'}) - }) - - return numa_capability - - def _get_storage_capabilities(self, flavor): - storage_capability = {} - feature_uuid = uuid.uuid4() - - storage_capability['hpa-capability-id'] = str(feature_uuid) - storage_capability['hpa-feature'] = 'localStorage' - storage_capability['architecture'] = 'generic' - storage_capability['hpa-version'] = 'v1' - - storage_capability['hpa-feature-attributes'] = [] - storage_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'diskSize', - 'hpa-attribute-value': json.dumps({'value': str( - flavor['disk']), 'unit': 'GB'}) - }) - storage_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'swapMemSize', - 'hpa-attribute-value': json.dumps({'value': str( - flavor.get('swap', 0)), 'unit': 'MB'}) - }) - storage_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'ephemeralDiskSize', - 'hpa-attribute-value': json.dumps({'value': str( - flavor.get('OS-FLV-EXT-DATA:ephemeral', 0)), 'unit': 'GB'}) - }) - return storage_capability - - def _get_instruction_set_capabilities(self, extra_specs): - instruction_capability = {} - feature_uuid = uuid.uuid4() - - if extra_specs.get('hw:capabilities:cpu_info:features'): - instruction_capability['hpa-capability-id'] = str(feature_uuid) - instruction_capability['hpa-feature'] = 'instructionSetExtensions' - instruction_capability['architecture'] = 'Intel64' - instruction_capability['hpa-version'] = 'v1' - - instruction_capability['hpa-feature-attributes'] = [] - instruction_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'instructionSetExtensions', - 'hpa-attribute-value': json.dumps( - {'value': extra_specs[ - 'hw:capabilities:cpu_info:features']}) - }) - return instruction_capability - - def _get_pci_passthrough_capabilities(self, extra_specs): - instruction_capability = {} - feature_uuid = uuid.uuid4() - - if extra_specs.get('pci_passthrough:alias'): - value1 = extra_specs['pci_passthrough:alias'].split(':') - value2 = value1[0].split('-') - - instruction_capability['hpa-capability-id'] = str(feature_uuid) - instruction_capability['hpa-feature'] = 'pciePassthrough' - instruction_capability['architecture'] = str(value2[2]) - instruction_capability['hpa-version'] = 'v1' - - instruction_capability['hpa-feature-attributes'] = [] - instruction_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'pciCount', - 'hpa-attribute-value': json.dumps({'value': value1[1]}) - }) - instruction_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'pciVendorId', - 'hpa-attribute-value': json.dumps({'value': value2[3]}) - }) - instruction_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': 'pciDeviceId', - 'hpa-attribute-value': json.dumps({'value': value2[4]}) - }) - - return instruction_capability - - def _get_ovsdpdk_capabilities(self): - ovsdpdk_capability = {} - feature_uuid = uuid.uuid4() - - if not self._vim_info: - self._vim_info = self.get_vim(get_all=True) - cloud_extra_info_str = self._vim_info.get('cloud-extra-info') - if not isinstance(cloud_extra_info_str, dict): - try: - cloud_extra_info_str = json.loads(cloud_extra_info_str) - except Exception as ex: - logger.error("Can not convert cloud extra info %s %s" % ( - str(ex), cloud_extra_info_str)) - return {} - if cloud_extra_info_str: - cloud_dpdk_info = cloud_extra_info_str.get("ovsDpdk") - if cloud_dpdk_info: - ovsdpdk_capability['hpa-capability-id'] = str(feature_uuid) - ovsdpdk_capability['hpa-feature'] = 'ovsDpdk' - ovsdpdk_capability['architecture'] = 'Intel64' - ovsdpdk_capability['hpa-version'] = 'v1' - - ovsdpdk_capability['hpa-feature-attributes'] = [] - ovsdpdk_capability['hpa-feature-attributes'].append({ - 'hpa-attribute-key': str(cloud_dpdk_info.get("libname")), - 'hpa-attribute-value': json.dumps( - {'value': cloud_dpdk_info.get("libversion")}) - }) - return ovsdpdk_capability diff --git a/azure/azure/pub/utils/syscomm.py b/azure/azure/pub/utils/syscomm.py deleted file mode 100644 index f838956..0000000 --- a/azure/azure/pub/utils/syscomm.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import inspect -import json -from collections import defaultdict -from rest_framework import status - - -keystoneV2Json = \ - { - "auth": { - "tenantName": "", - "passwordCredentials": { - "username": "", - "password": "" - } - } - } - - -SUCCESS_STATE = [status.HTTP_200_OK, status.HTTP_201_CREATED, - status.HTTP_202_ACCEPTED] - - -def fun_name(): - return inspect.stack()[1][3] - - -def jsonResponse(data, encoding='utf-8'): - - content_type = "application/json" - try: - res = json.loads(data, encoding=encoding) - except Exception: - res = data - content_type = "text/plain" - return (res, content_type) - - -class Catalogs(object): - - def __init__(self): - self.ct = defaultdict(dict) - - def storeEndpoint(self, vimid, endpoints): - if vimid in self.ct: - self.ct[vimid].update(endpoints) - else: - self.ct.setdefault(vimid, endpoints) - - def getEndpointBy(self, vimid, serverType, interface='public'): - - vim = self.ct.get(vimid) - return vim.get(serverType).get(interface, "") if vim else "" - - -def verifyKeystoneV2(param): - - return _walk_json(param, keystoneV2Json) - - -# comapare two json by key -def _walk_json(data, data2): - if isinstance(data, dict) and isinstance(data2, dict): - if set(data.keys()) != set(data2.keys()): - return False - else: - v1 = data.values() - v2 = data2.values() - v1.sort() - v2.sort() - if len(v1) != len(v2): - return False - for (i, j) in zip(v1, v2): - # continue compare key - if isinstance(i, dict) and isinstance(j, dict): - if not _walk_json(i, j): - return False - # ignore value - else: - continue - - return True - - return False - - -def keystoneVersion(url, version="v3"): - - tmp = url.split("/") - v = tmp[-1] - if v not in ["v2.0", "v3"]: - url += "/" + version - else: - tmp[-1] = version - url = "/".join(tmp) - - return url - - -catalog = Catalogs() diff --git a/azure/azure/pub/utils/timeutil.py b/azure/azure/pub/utils/timeutil.py deleted file mode 100644 index d5ef329..0000000 --- a/azure/azure/pub/utils/timeutil.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import datetime - - -def now_time(fmt="%Y-%m-%d %H:%M:%S"): - return datetime.datetime.now().strftime(fmt) diff --git a/azure/azure/pub/utils/values.py b/azure/azure/pub/utils/values.py deleted file mode 100644 index 61d7114..0000000 --- a/azure/azure/pub/utils/values.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -def ignore_case_get(args, key, def_val=""): - if not key: - return def_val - if key in args: - return args[key] - for old_key in args: - if old_key.upper() == key.upper(): - return args[old_key] - return def_val diff --git a/azure/azure/pub/vim/__init__.py b/azure/azure/pub/vim/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/pub/vim/const.py b/azure/azure/pub/vim/const.py deleted file mode 100644 index dc5a3a4..0000000 --- a/azure/azure/pub/vim/const.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -SAMPLE_KEY = "sample_value" diff --git a/azure/azure/samples/__init__.py b/azure/azure/samples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/samples/tests.py b/azure/azure/samples/tests.py deleted file mode 100644 index e801e48..0000000 --- a/azure/azure/samples/tests.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: - -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import unittest -import json -from django.test import Client -from rest_framework import status - - -class SampleViewTest(unittest.TestCase): - def setUp(self): - self.client = Client() - - def tearDown(self): - pass - - def test_sample(self): - response = self.client.get("/samples/") - self.assertEqual(status.HTTP_200_OK, - response.status_code, response.content) - resp_data = json.loads(response.content) - self.assertEqual("active", resp_data["status"]) diff --git a/azure/azure/samples/urls.py b/azure/azure/samples/urls.py deleted file mode 100644 index 39da376..0000000 --- a/azure/azure/samples/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: - -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from django.conf.urls import url -from azure.samples import views - -urlpatterns = [ - url(r'^samples/$', views.SampleList.as_view()), ] diff --git a/azure/azure/samples/views.py b/azure/azure/samples/views.py deleted file mode 100644 index 6576450..0000000 --- a/azure/azure/samples/views.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: - -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import os -import logging - -from rest_framework.views import APIView -from rest_framework.response import Response - -logger = logging.getLogger(__name__) -log_file = "/var/log/onap/multicloud/azure/azure.log" - - -class SampleList(APIView): - """ - List all samples. - """ - - def get(self, request, format=None): - logger.debug("get") - output = "" - if os.path.exists(log_file): - with open("/var/log/onap/multicloud/azure/azure.log", "r") as f: - lines = f.readlines() - output = lines[-1] - return Response({"status": "active", "logs": output}) diff --git a/azure/azure/scripts/__init__.py b/azure/azure/scripts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/scripts/api.py b/azure/azure/scripts/api.py deleted file mode 100644 index 792fd5d..0000000 --- a/azure/azure/scripts/api.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import eventlet -eventlet.monkey_patch() - -import os # noqa -from oslo_config import cfg # noqa -from oslo_service import service # noqa -import sys # noqa -# FIXME: Since there is no explicitly setup process for the project. Hack the -# python here. -sys.path.append(os.path.abspath('.')) - -from azure.api_v2 import service as api_service # noqa - - -def main(): - try: - api_server = api_service.WSGIService() - launcher = service.launch(cfg.CONF, - api_server, - workers=api_server.workers) - launcher.wait() - except RuntimeError as excp: - sys.stderr.write("ERROR: %s\n" % excp) - sys.exit(1) - - -if __name__ == '__main__': - main() diff --git a/azure/azure/settings-cover.py b/azure/azure/settings-cover.py deleted file mode 100644 index b4fecdd..0000000 --- a/azure/azure/settings-cover.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from azure.settings import * # noqa -from azure.settings import INSTALLED_APPS - -INSTALLED_APPS.append('django_nose') - -TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' - -NOSE_ARGS = [ - '--with-coverage', - '--cover-package=azure', -] diff --git a/azure/azure/settings.py b/azure/azure/settings.py deleted file mode 100644 index ace6e8f..0000000 --- a/azure/azure/settings.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import os -import sys -from logging import config -from onaplogging import monkey -monkey.patch_all() - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '3o-wney!99y)^h3v)0$j16l9=fdjxcb+a8g+q3tfbahcnu2b0o' - -# SECURITY WARNING: don't run with debug turned on in production! -# DEBUG = True - -ALLOWED_HOSTS = ['*'] - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', - 'azure.pub.database', -] - -MIDDLEWARE_CLASSES = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'azure.middleware.LogContextMiddleware', -] - -ROOT_URLCONF = 'azure.urls' - -WSGI_APPLICATION = 'azure.wsgi.application' - -REST_FRAMEWORK = { - 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.JSONRenderer', - ), - - 'DEFAULT_PARSER_CLASSES': ( - 'rest_framework.parsers.JSONParser', - 'rest_framework.parsers.MultiPartParser', - # 'rest_framework.parsers.FormParser', - # 'rest_framework.parsers.FileUploadParser', - ) -} - - -TIME_ZONE = 'UTC' - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.6/howto/static-files/ - -STATIC_URL = '/static/' - - -LOGGING_CONFIG = None -# yaml configuration of logging -LOGGING_FILE = os.path.join(BASE_DIR, 'azure/pub/config/log.yml') -config.yamlConfig(filepath=LOGGING_FILE, watchDog=True) - - -if 'test' in sys.argv: - from azure.pub.config import config - REST_FRAMEWORK = {} - import platform - - if platform.system() == 'Linux': - TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' - TEST_OUTPUT_VERBOSE = True - TEST_OUTPUT_DESCRIPTIONS = True - TEST_OUTPUT_DIR = 'test-reports' diff --git a/azure/azure/swagger/__init__.py b/azure/azure/swagger/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/swagger/image_utils.py b/azure/azure/swagger/image_utils.py deleted file mode 100644 index a17565e..0000000 --- a/azure/azure/swagger/image_utils.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -def image_formatter(image): - - image = image.to_dict() - properties = {} - if image.get("vmware_adaptertype"): - properties['vmware_adaptertype'] = image.get("vmware_adaptertype") - if image.get("vmware_ostype"): - properties['vmware_ostype'] = image.get("vmware_ostype") - - return { - 'id': image.get("id"), - 'name': image.get("name"), - 'imageType': image.get("disk_format"), - 'status': image.get("status"), - 'size': image.get("size"), - 'containerFormat': image.get("container_format"), - 'visibility': image.get("visibility"), - 'properties': properties - } - - -def vim_formatter(vim_info, tenantid): - - rsp = {} - rsp['vimId'] = vim_info.get('vimId') - rsp['vimName'] = vim_info.get('name') - rsp['tenantId'] = tenantid - return rsp - - -def sdk_param_formatter(data): - - param = {} - param['username'] = data.get('userName') - param['password'] = data.get('password') - param['auth_url'] = data.get('url') - param['project_id'] = data.get('tenant') - param['user_domain_name'] = 'default' - param['project_domain_name'] = 'default' - return param - - -def req_body_formatter(body): - - param = {} - param['name'] = body.get('name') - param['disk_format'] = body.get('imageType') - param['container_format'] = body.get('containerFormat') - param['visibility'] = body.get('visibility') - properties = body.get('properties', {}) - param.update(properties) - return param diff --git a/azure/azure/swagger/tests.py b/azure/azure/swagger/tests.py deleted file mode 100644 index 4631455..0000000 --- a/azure/azure/swagger/tests.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import unittest -# import json -from django.test import Client -from rest_framework import status - - -class SampleViewTest(unittest.TestCase): - def setUp(self): - self.client = Client() - - def tearDown(self): - pass - - def test_sample(self): - response = self.client.get("/api/multicloud-azure/v0/swagger.json") - self.assertEqual(status.HTTP_200_OK, - response.status_code, response.content) -# resp_data = json.loads(response.content) -# self.assertEqual({"status": "active"}, resp_data) diff --git a/azure/azure/swagger/urls.py b/azure/azure/swagger/urls.py deleted file mode 100644 index f80fa26..0000000 --- a/azure/azure/swagger/urls.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2018 Amdocs -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from django.conf.urls import url -from rest_framework.urlpatterns import format_suffix_patterns - -from azure.swagger.views.swagger_json import SwaggerJsonView - - -# Registry -from azure.swagger.views.registry.views import Registry -from azure.swagger.views.registry.views import UnRegistry - - -urlpatterns = [ - # swagger - url(r'^api/multicloud-azure/v0/swagger.json$', SwaggerJsonView.as_view()), - - # Registry - url(r'^api/multicloud-azure/v0/(?P[0-9a-z-A-Z\-\_]+)/registry$', - Registry.as_view()), - url(r'^api/multicloud-azure/v0/(?P[0-9a-z-A-Z\-\_]+)$', - UnRegistry.as_view()), - -] - -urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/azure/azure/swagger/utils.py b/azure/azure/swagger/utils.py deleted file mode 100644 index cb7e4f0..0000000 --- a/azure/azure/swagger/utils.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import os - - -def get_swagger_json_data(): - json_file = os.path.join(os.path.dirname( - __file__), 'multivim.flavor.swagger.json') - f = open(json_file) - json_data = json.JSONDecoder().decode(f.read()) - f.close() - # json_file = os.path.join(os.path.dirname( - # __file__), 'multivim.image.swagger.json') - # f = open(json_file) - # json_data_temp = json.JSONDecoder().decode(f.read()) - # f.close() - # json_data["paths"].update(json_data_temp["paths"]) - # json_data["definitions"].update(json_data_temp["definitions"]) - - json_data["basePath"] = "/api/multicloud-azure/v0/" - json_data["info"]["title"] = "MultiVIM driver \ - of Microsoft Azure Service NBI" - - return json_data diff --git a/azure/azure/swagger/views.py b/azure/azure/swagger/views.py deleted file mode 100644 index f0b7028..0000000 --- a/azure/azure/swagger/views.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import logging -# import traceback - -# from rest_framework import status -from rest_framework.response import Response -from rest_framework.views import APIView - -# from azure.pub.exceptions import VimDriverAzureException -from azure.swagger import utils - -logger = logging.getLogger(__name__) - - -class SwaggerJsonView(APIView): - def get(self, request): - - return Response(utils.get_swagger_json_data()) diff --git a/azure/azure/swagger/views/__init__.py b/azure/azure/swagger/views/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/swagger/views/multivim.swagger.json b/azure/azure/swagger/views/multivim.swagger.json deleted file mode 100644 index de3419f..0000000 --- a/azure/azure/swagger/views/multivim.swagger.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "1.0.0", - "title": "MultiVIM Service rest API" - }, - "basePath": "/api/multicloud-azure/v0/", - "tags": [ - { - "name": "MultiVIM Azure services" - } - ], - "paths": { - "/{vimid}/registry": { - "post": { - "tags": [ - "vim registration" - ], - "summary": "vim registration API", - "description": "vim registration API", - "operationId": "vim_registration", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "parameters": [ - { - "name": "vimid", - "in": "path", - "description": "vim instance id", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "successful operation" - }, - "404": { - "description": "the vim id is wrong" - }, - "500": { - "description": "error occured during the process" - } - } - } - } - } -} diff --git a/azure/azure/swagger/views/registry/__init__.py b/azure/azure/swagger/views/registry/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/swagger/views/registry/views.py b/azure/azure/swagger/views/registry/views.py deleted file mode 100644 index b5db805..0000000 --- a/azure/azure/swagger/views/registry/views.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -import logging - -from rest_framework import status -from rest_framework.response import Response -from rest_framework.views import APIView - -from azure.pub.exceptions import VimDriverAzureException -from azure.pub.msapi import extsys -from azure.pub.utils.restcall import AAIClient - - -logger = logging.getLogger(__name__) - - -class Registry(APIView): - # def _get_tenants(self, auth_info): - # tenant_instance = OperateTenant.OperateTenant() - # try: - # projects = tenant_instance.get_projects(auth_info) - # except Exception as e: - # logger.exception("get tenants error %(e)s", {"e": e}) - # raise e - # - # rsp = {"tenants": []} - # for project in projects: - # rsp['tenants'].append(project.to_dict()) - # return rsp - # - # def _get_images(self, auth_info): - # image_instance = OperateImage.OperateImage(auth_info) - # try: - # images = image_instance.get_vim_images() - # except Exception as e: - # logger.exception("get images error %(e)s", {"e": e}) - # raise e - # - # rsp = {"images": []} - # for image in images: - # rsp['images'].append(image.to_dict()) - # return rsp - # - # def _get_flavors(self, auth_info): - # flavors_op = OperateFlavors.OperateFlavors() - # try: - # flavors = flavors_op.list_flavors( - # auth_info, auth_info['tenant']) - # except Exception as e: - # logger.exception("get flavors error %(e)s", {"e": e}) - # raise e - # - # rsp = {"flavors": []} - # for flavor in flavors: - # flavor_info = flavor[0].to_dict() - # flavor_info['extra_specs'] = flavor[1].extra_specs - # rsp['flavors'].append(flavor_info) - # return rsp - # - # def _get_networks(self, auth_info): - # net_op = OperateNetwork.OperateNetwork() - # try: - # resp = net_op.list_networks( - # auth_info['vimId'], auth_info['tenant']) - # except Exception as e: - # logger.exception("get networks error %(e)s", {"e": e}) - # raise e - # - # rsp = {'networks': resp['networks']} - # return rsp - # - # def _get_hypervisors(self, auth_info): - # hypervisor_op = OperateHypervisor.OperateHypervisor() - # try: - # hypervisors = hypervisor_op.list_hypervisors(auth_info) - # except Exception as e: - # logger.exception("get hypervisors error %(e)s", {"e": e}) - # raise e - # - # rsp = {"hypervisors": []} - # for hypervisor in hypervisors: - # rsp['hypervisors'].append(hypervisor.to_dict()) - # return rsp - - def _find_tenant_id(self, name, tenants): - for tenant in tenants['tenants']: - if tenant['name'] == name: - return tenant['id'] - - def post(self, request, vimid): - try: - vim_info = extsys.get_vim_by_id(vimid) - except VimDriverAzureException as e: - return Response(data={'error': str(e)}, status=e.status_code) - data = {} - data['vimId'] = vim_info['vimId'] - data['username'] = vim_info['userName'] - data['userName'] = vim_info['userName'] - data['password'] = vim_info['password'] - data['url'] = vim_info['url'] - data['project_name'] = vim_info['tenant'] - - rsp = {} - # get tenants - try: - logger.debug('Getting tenants') - tenants = self._get_tenants(data) - rsp.update(tenants) - data['tenant'] = self._find_tenant_id( - data['project_name'], tenants) - data['project_id'] = data['tenant'] - # set default tenant - # get images - logger.debug('Getting images') - images = self._get_images(data) - rsp.update(images) - # get flavors - logger.debug('Getting flavors') - flavors = self._get_flavors(data) - rsp.update(flavors) - # get networks - logger.debug('Getting networks') - networks = self._get_networks(data) - rsp.update(networks) - # get hypervisors - logger.debug('Getting hypervisors') - hypervisors = self._get_hypervisors(data) - rsp.update(hypervisors) - # update A&AI - logger.debug('Put data into A&AI') - cloud_owner, cloud_region = extsys.split_vim_to_owner_region( - vimid) - aai_adapter = AAIClient(cloud_owner, cloud_region) - aai_adapter.update_vim(rsp) - except Exception as e: - if hasattr(e, "http_status"): - return Response(data={'error': str(e)}, status=e.http_status) - else: - return Response(data={'error': str(e)}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - return Response(data="", status=status.HTTP_200_OK) - - -class UnRegistry(APIView): - - def delete(self, request, vimid): - try: - cloud_owner, cloud_region = extsys.split_vim_to_owner_region( - vimid) - aai_adapter = AAIClient(cloud_owner, cloud_region) - aai_adapter.delete_vim() - except Exception as e: - return Response(data=e.message, - status=status.HTTP_500_INTERNAL_SERVER_ERROR) - return Response(data="", status=status.HTTP_204_NO_CONTENT) diff --git a/azure/azure/swagger/views/swagger_json.py b/azure/azure/swagger/views/swagger_json.py deleted file mode 100644 index 91c00dd..0000000 --- a/azure/azure/swagger/views/swagger_json.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: - -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -import json -import logging -import os - -from rest_framework.response import Response -from rest_framework.views import APIView - - -logger = logging.getLogger(__name__) - - -class SwaggerJsonView(APIView): - def get(self, request): - json_file = os.path.join(os.path.dirname( - __file__), 'multivim.swagger.json') - f = open(json_file) - json_data = json.JSONDecoder().decode(f.read()) - f.close() - # json_file = os.path.join(os.path.dirname( - # __file__), 'multivim.image.swagger.json') - # f = open(json_file) - # json_data_temp = json.JSONDecoder().decode(f.read()) - # f.close() - # json_data["paths"].update(json_data_temp["paths"]) - # json_data["definitions"].update(json_data_temp["definitions"]) - json_data["basePath"] = "/api/multicloud-azure/v0/" - json_data["info"]["title"] = "MultiVIM \ - driver of Microsoft Azure Service NBI" - return Response(json_data) diff --git a/azure/azure/swagger/volume_utils.py b/azure/azure/swagger/volume_utils.py deleted file mode 100644 index ae11285..0000000 --- a/azure/azure/swagger/volume_utils.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -def volume_formatter(volume): - - attachments = [] - for attach in volume.attachments: - vim_attach = { - 'device': attach['device'], - 'volumeId': attach['volume_id'], - 'hostName': attach['host_name'], - 'Id': attach['attachment_id'], - 'serverId': attach['server_id'] - } - attachments.append(vim_attach) - - return { - 'id': volume.id, - 'name': volume.name, - 'createTime': volume.created_at, - 'status': volume.status, - 'type': volume.volume_type, - 'size': volume.size, - 'availabilityZone': volume.availability_zone, - 'attachments': attachments - } - - -def vim_formatter(vim_info, tenantid): - - rsp = {} - rsp['vimId'] = vim_info.get('vimId') - rsp['vimName'] = vim_info.get('name') - rsp['tenantId'] = tenantid - return rsp - - -def sdk_param_formatter(data): - - param = {} - param['username'] = data.get('userName') - param['password'] = data.get('password') - param['auth_url'] = data.get('url') - param['project_id'] = data.get('tenant') - param['user_domain_name'] = 'default' - param['project_domain_name'] = 'default' - return param - - -def req_body_formatter(body): - - param = {} - param['name'] = body.get('name') - param['size'] = body.get('volumeSize') - - if body.get('volumeType'): - param['volume_type'] = body.get('volumeType') - if body.get('availabilityZone'): - param['availability_zone'] = body.get('availabilityZone') - if body.get('imageId'): - param['image_id'] = body.get('imageId') - return param diff --git a/azure/azure/tests/__init__.py b/azure/azure/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/azure/azure/tests/test_aai_client.py b/azure/azure/tests/test_aai_client.py deleted file mode 100644 index 31ff37d..0000000 --- a/azure/azure/tests/test_aai_client.py +++ /dev/null @@ -1,378 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import json -import mock -import unittest - -from azure.pub.exceptions import VimDriverAzureException -from azure.pub.utils import restcall - - -class TestAAIClient(unittest.TestCase): - - def setUp(self): - self.view = restcall.AAIClient("vmware", "4.0") - - @mock.patch.object(restcall, "call_req") - def test_get_vim(self, mock_call): - mock_call.return_value = [0, '{"cloudOwner": "vmware"}'] - ret = self.view.get_vim(get_all=True) - expect_ret = {"cloudOwner": "vmware"} - self.assertEqual(expect_ret, ret) - - @mock.patch.object(restcall.AAIClient, "get_vim") - @mock.patch.object(restcall, "call_req") - def test_update_identity_url(self, mock_call, mock_getvim): - mock_getvim.return_value = {} - self.view.update_identity_url() - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_tenants(self, mock_call): - tenants = {"tenants": [{"name": "admin", "id": "admin-id"}]} - self.view.add_tenants(tenants) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_flavors(self, mock_call): - flavors = { - "flavors": [{ - "name": "m1.small", - "id": "1", - "vcpus": 1, - "ram": 512, - "disk": 10, - "ephemeral": 0, - "swap": 0, - "is_public": True, - "links": [{"href": "http://fake-url"}], - "is_disabled": False - }] - } - self.view.add_flavors(flavors) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_flavors_with_hpa(self, mock_call): - flavors = { - "flavors": [{ - "name": "onap.small", - "id": "1", - "vcpus": 1, - "ram": 512, - "disk": 10, - "ephemeral": 0, - "swap": 0, - "is_public": True, - "links": [{"href": "http://fake-url"}], - "is_disabled": False, - "extra_specs": {}, - }] - } - self.view._get_ovsdpdk_capabilities = mock.MagicMock() - self.view._get_ovsdpdk_capabilities.return_value = {} - self.view.add_flavors(flavors) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_images(self, mock_call): - images = { - "images": [{ - "name": "ubuntu-16.04", - "id": "image-id" - }] - } - self.view.add_images(images) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_networks(self, mock_call): - networks = { - "networks": [{ - "name": "net-1", - "id": "net-id", - "segmentationId": 144 - }] - } - self.view.add_networks(networks) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_pservers(self, mock_call): - pservers = { - "hypervisors": [{ - "name": "compute-1", - "vcpus": 100, - "local_disk_size": 1000, - "memory_size": 10240, - "host_ip": "10.0.0.7", - "id": "compute-1-id" - }] - } - self.view.add_pservers(pservers) - self.assertEqual(mock_call.call_count, 2) - - @mock.patch.object(restcall, "call_req") - def test_del_tenants(self, mock_call): - mock_call.return_value = [0] - rsp = { - "tenants": { - "tenant": [{ - "tenant-id": "tenant-id", - "resource-version": "version-1" - }] - } - } - self.view._del_tenants(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_flavors(self, mock_call): - mock_call.return_value = [0] - rsp = { - "flavors": { - "flavor": [{ - "flavor-id": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_flavors(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_images(self, mock_call): - mock_call.return_value = [0] - rsp = { - "images": { - "image": [{ - "image-id": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_images(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_networks(self, mock_call): - mock_call.return_value = [0] - rsp = { - "oam-networks": { - "oam-network": [{ - "network-uuid": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_networks(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_azs(self, mock_call): - mock_call.return_value = [0] - rsp = { - "availability-zones": { - "availability-zone": [{ - "availability-zone-name": "fake-name", - "resource-version": "fake-version" - }] - } - } - self.view._del_azs(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_hpa(self, mock_call): - mock_call.return_value = [0] - rsp = { - "flavor-id": "id1", - "hpa-capabilities": { - "hpa-capability": [{ - "resource-version": "v1", - "hpa-capability-id": "id2" - }] - } - } - self.view._del_hpa(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_vim(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - mock_call.return_value = [0, "", "", ""] - self.view.delete_vim() - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_vim_fail(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - mock_call.return_value = [1, "", "", ""] - self.assertRaises(VimDriverAzureException, self.view.delete_vim) - - @mock.patch.object(restcall, "call_req") - def test_update_vim(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - content = { - "tenants": [], - "images": [], - "flavors": [], - "networks": [], - "hypervisors": [] - } - self.view.update_vim(content) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_get_hpa(self, mock_call): - self.view._get_hpa_basic_capabilities = mock.MagicMock() - self.view._get_hpa_basic_capabilities.return_value = {"hpa": "basic"} - self.view._get_cpupinning_capabilities = mock.MagicMock() - self.view._get_cpupinning_capabilities.return_value = {"hpa": "basic"} - self.view._get_cputopology_capabilities = mock.MagicMock() - self.view._get_cputopology_capabilities.return_value = {"hpa": "basic"} - self.view._get_hugepages_capabilities = mock.MagicMock() - self.view._get_hugepages_capabilities.return_value = {"hpa": "basic"} - self.view._get_numa_capabilities = mock.MagicMock() - self.view._get_numa_capabilities.return_value = {"hpa": "basic"} - self.view._get_storage_capabilities = mock.MagicMock() - self.view._get_storage_capabilities.return_value = {"hpa": "basic"} - self.view._get_instruction_set_capabilities = mock.MagicMock() - self.view._get_instruction_set_capabilities.return_value = { - "hpa": "basic"} - self.view._get_pci_passthrough_capabilities = mock.MagicMock() - self.view._get_pci_passthrough_capabilities.return_value = { - "hpa": "basic"} - self.view._get_ovsdpdk_capabilities = mock.MagicMock() - self.view._get_ovsdpdk_capabilities.return_value = {"hpa": "basic"} - ret = self.view._get_hpa_capabilities({"extra_specs": {}}) - self.assertEqual([{"hpa": "basic"}]*9, ret) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_basic(self, mock_call): - flavor = { - "vcpus": 1, - "ram": 1024 - } - ret = self.view._get_hpa_basic_capabilities(flavor) - self.assertEqual(len(ret["hpa-feature-attributes"]), 2) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_cpupin(self, mock_call): - extra = { - "hw:cpu_policy": "cpu_policy", - "hw:cpu_thread_policy": "thread_policy" - } - ret = self.view._get_cpupinning_capabilities(extra) - self.assertEqual(len(ret["hpa-feature-attributes"]), 2) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_cputopo(self, mock_call): - extra = { - "hw:cpu_sockets": 2, - "hw:cpu_cores": 2, - "hw:cpu_threads": 4 - } - ret = self.view._get_cputopology_capabilities(extra) - self.assertEqual(len(ret["hpa-feature-attributes"]), 3) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_large(self, mock_call): - extra = { - "hw:mem_page_size": "large" - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "2", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_small(self, mock_call): - extra = { - "hw:mem_page_size": "small" - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "4", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_int(self, mock_call): - extra = { - "hw:mem_page_size": 8, - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "8", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_any(self, mock_call): - extra = { - "hw:mem_page_size": "any", - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertEqual(0, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_numa(self, mock_call): - extra = { - "hw:numa_nodes": 1, - "hw:numa_cpus.0": 1, - "hw:numa_mem.0": 1024, - } - ret = self.view._get_numa_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_storage(self, mock_call): - extra = { - "disk": 10, - } - ret = self.view._get_storage_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_instru(self, mock_call): - extra = { - "hw:capabilities:cpu_info:features": "avx", - } - ret = self.view._get_instruction_set_capabilities(extra) - self.assertEqual(1, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_pci(self, mock_call): - extra = { - "pci_passthrough:alias": "gpu-nvidia-x86-0011-0022:1", - } - ret = self.view._get_pci_passthrough_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_dpdk(self, mock_call): - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = { - "cloud-extra-info": json.dumps({'ovsDpdk': { - 'libname': 'generic', 'libversion': '17.04'}}) - } - ret = self.view._get_ovsdpdk_capabilities() - self.assertEqual(1, len(ret["hpa-feature-attributes"])) diff --git a/azure/azure/tests/test_restcall.py b/azure/azure/tests/test_restcall.py deleted file mode 100644 index bf45ccf..0000000 --- a/azure/azure/tests/test_restcall.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) 2018 Amdocs -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import mock -import unittest -import urllib2 - -from azure.pub.utils import restcall - - -class TestRestCall(unittest.TestCase): - - def test_combine_url(self): - url = ["http://a.com/test/", "http://a.com/test/", - "http://a.com/test", "http://a.com/test"] - res = ["/resource", "resource", "/resource", "resource"] - expected = "http://a.com/test/resource" - for i in range(len(url)): - self.assertEqual(expected, restcall.combine_url(url[i], res[i])) - - @mock.patch.object(restcall, "call_req") - def test_get_res_from_aai(self, mock_call): - res = "cloud-regions" - content = "" - expect_url = "https://aai.api.simpledemo.openecomp.org:8443/aai/v13" - expect_user = "AAI" - expect_pass = "AAI" - expect_headers = { - 'X-FromAppId': 'MultiCloud', - 'X-TransactionId': '9001', - 'content-type': 'application/json', - 'accept': 'application/json' - } - restcall.get_res_from_aai(res, content=content) - mock_call.assert_called_once_with( - expect_url, expect_user, expect_pass, restcall.rest_no_auth, - res, "GET", content, expect_headers) - - @mock.patch.object(restcall, "call_req") - def test_req_by_msb(self, mock_call): - res = "multicloud" - method = "GET" - content = "no content" - restcall.req_by_msb(res, method, content=content) - expect_url = "http://msb.onap.org:10080/" - mock_call.assert_called_once_with( - expect_url, "", "", restcall.rest_no_auth, res, method, - content) - - @mock.patch("httplib2.Http.request") - def test_call_req_success(self, mock_req): - mock_resp = { - "status": "200" - } - resp_content = "hello" - mock_req.return_value = mock_resp, resp_content - expect_ret = [0, resp_content, "200", mock_resp] - ret = restcall.call_req("http://onap.org/", "user", "pass", - restcall.rest_no_auth, "vim", "GET") - self.assertEqual(expect_ret, ret) - - @mock.patch("httplib2.Http.request") - def test_call_req_not_200(self, mock_req): - mock_resp = { - "status": "404" - } - resp_content = "hello" - mock_req.return_value = mock_resp, resp_content - expect_ret = [1, resp_content, "404", mock_resp] - ret = restcall.call_req("http://onap.org/", "user", "pass", - restcall.rest_no_auth, "vim", "GET") - self.assertEqual(expect_ret, ret) - - @mock.patch("traceback.format_exc") - @mock.patch("sys.exc_info") - @mock.patch("httplib2.Http.request") - def test_call_req_response_not_ready(self, mock_req, mock_sys, - mock_traceback): - mock_sys.return_value = "httplib.ResponseNotReady" - mock_req.side_effect = [Exception("httplib.ResponseNotReady")] * 3 - expect_ret = [1, "Unable to connect to http://onap.org/vim", "", ""] - ret = restcall.call_req("http://onap.org/", "user", "pass", - restcall.rest_no_auth, "vim", "GET") - self.assertEqual(expect_ret, ret) - self.assertEqual(3, mock_req.call_count) - - @mock.patch("httplib2.Http.request") - def test_call_req_url_err(self, mock_req): - urlerr = urllib2.URLError("urlerror") - mock_req.side_effect = [urlerr] - expect_ret = [2, str(urlerr), "", ""] - ret = restcall.call_req("http://onap.org/", "user", "pass", - restcall.rest_no_auth, "vim", "GET") - self.assertEqual(expect_ret, ret) diff --git a/azure/azure/tests/test_syscomm.py b/azure/azure/tests/test_syscomm.py deleted file mode 100644 index d700ed7..0000000 --- a/azure/azure/tests/test_syscomm.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -import unittest - -from azure.pub.utils import syscomm - - -class SyscommTest(unittest.TestCase): - - def test_keystone_version(self): - url = "http://a.com/test" - version = "v3" - expected = "http://a.com/test/v3" - self.assertEquals(expected, syscomm.keystoneVersion(url, version)) - - def test_verify_keystone(self): - param = \ - { - "auth": { - "tenantName": "12345", - "passwordCredentials": { - "username": "admin", - "password": "admin" - } - } - } - self.assertEquals(True, syscomm.verifyKeystoneV2(param)) diff --git a/azure/azure/urls.py b/azure/azure/urls.py deleted file mode 100644 index 028f008..0000000 --- a/azure/azure/urls.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -from django.conf.urls import include, url - -urlpatterns = [ - url(r'^', include('azure.swagger.urls')), - url(r'^', include('azure.samples.urls')), -] diff --git a/azure/azure/wsgi.py b/azure/azure/wsgi.py deleted file mode 100644 index 355b604..0000000 --- a/azure/azure/wsgi.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "azure.settings") - -application = get_wsgi_application() diff --git a/azure/manage.py b/azure/manage.py index 4a98417..9b219de 100644 --- a/azure/manage.py +++ b/azure/manage.py @@ -13,7 +13,7 @@ import os import sys -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "azure.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "multicloud_azure.settings") if __name__ == "__main__": from django.core.management import execute_from_command_line diff --git a/azure/multicloud_azure/__init__.py b/azure/multicloud_azure/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/api_v2/__init__.py b/azure/multicloud_azure/api_v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/api_v2/api_definition/__init__.py b/azure/multicloud_azure/api_v2/api_definition/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/api_v2/api_definition/hosts.yaml b/azure/multicloud_azure/api_v2/api_definition/hosts.yaml new file mode 100644 index 0000000..88eaa09 --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/hosts.yaml @@ -0,0 +1,72 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Host" + description: "Definition of Host API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/hosts/{hostid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: hostid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/host" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/host" + vim_path: "/compute/os-hypervisors" + definitions: + host: + plural_vim_resource: "hypervisors" + vim_resource: "hypervisor" + plural: "hosts" + properties: + name: + type: string + required: true + source: hypervisor.hypervisor_hostname + id: + type: string + required: true + source: hypervisor.id + status: + type: string + source: hypervisor.status + state: + type: string + source: hypervisor.state + cpu: + type: integer + minimal: 1 + source: hypervisor.vcpus + action: copy + disk_gb: + type: integer + minimal: 0 + source: hypervisor.local_gb + memory_mb: + type: integer + minimal: 0 + source: hypervisor.memory_mb diff --git a/azure/multicloud_azure/api_v2/api_definition/images.yaml b/azure/multicloud_azure/api_v2/api_definition/images.yaml new file mode 100644 index 0000000..723884c --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/images.yaml @@ -0,0 +1,76 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Image" + description: "Definition of Image API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/images/{imageid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: imageid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/image" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/image" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/image" + delete: + responses: "204" + vim_path: "/image/v2/images" + definitions: + image: + plural_vim_resource: "images" + vim_resource: "image" + plural: "images" + properties: + name: + type: string + required: true + source: image.name + id: + type: string + source: image.id + status: + type: string + source: image.status + imageType: + type: string + source: image.disk_format + containerFormat: + type: string + source: image.container_format + visibility: + type: string + source: image.visibility + size: + type: integer + source: image.size \ No newline at end of file diff --git a/azure/multicloud_azure/api_v2/api_definition/networks.yaml b/azure/multicloud_azure/api_v2/api_definition/networks.yaml new file mode 100644 index 0000000..c00808f --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/networks.yaml @@ -0,0 +1,91 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Network" + description: "Definition of Host API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/networks/{networkid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: networkid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/network" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/network" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/network" + delete: + responses: "204" + vim_path: "/network/v2.0/networks" + definitions: + network: + plural_vim_resource: "networks" + vim_resource: "network" + plural: "networks" + properties: + name: + type: string + required: true + source: network.name + id: + type: string + source: network.id + status: + type: string + source: network.status + segmentationId: + type: string + source: network.provider:segmentation_id + default: None + physicalNetwork: + type: string + source: network.provider:physical_network + default: None + networkType: + type: string + source: network.provider:network_type + default: None + tenantId: + type: string + source: network.tenant_id + shared: + type: boolean + source: network.shared + required: true + routerExternal: + type: boolean + source: network.router:external + required: true + vlanTransparent: + type: boolean + source: network.vlan_transparent + default: false diff --git a/azure/multicloud_azure/api_v2/api_definition/ports.yaml b/azure/multicloud_azure/api_v2/api_definition/ports.yaml new file mode 100644 index 0000000..e159593 --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/ports.yaml @@ -0,0 +1,83 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Port" + description: "Definition of Port API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/ports/{portid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: portid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/port" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + delete: + responses: "204" + vim_path: "/network/v2.0/ports" + definitions: + port: + plural_vim_resource: "ports" + vim_resource: "port" + plural: "port" + properties: + name: + type: string + required: true + source: port.name + id: + type: string + source: port.id + status: + type: string + source: port.status + networkId: + type: string + source: port.network_id + required: true + vnicType: + source: port.binding:vnic_type + securityGroups: + type: string + source: port.security_groups + tenantId: + type: string + source: port.tenant_id + macAddress: + type: string + source: port.mac_address + subnetId: + source: port.fixed_ips[0].subnet_id + ip: + source: port.fixed_ips[0].ip_address diff --git a/azure/multicloud_azure/api_v2/api_definition/subnets.yaml b/azure/multicloud_azure/api_v2/api_definition/subnets.yaml new file mode 100644 index 0000000..e48d570 --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/subnets.yaml @@ -0,0 +1,88 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Subnet" + description: "Definition of Subnet API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/subnets/{subnetid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: subnetid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/subnet" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/subnet" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/subnet" + delete: + responses: "204" + vim_path: "/network/v2.0/subnets" + definitions: + subnet: + plural_vim_resource: "subnets" + vim_resource: "subnet" + plural: "subnets" + properties: + name: + type: string + required: true + source: subnet.name + id: + type: string + source: subnet.id + status: + type: string + source: subnet.status + networkId: + type: string + source: subnet.network_id + required: true + allocationPools: + source: subnet.allocation_pools + gatewayIp: + type: string + source: subnet.gateway_ip + default: None + tenantId: + type: string + source: subnet.tenant_id + enableDhcp: + type: boolean + source: subnet.enable_dhcp + ipVersion: + source: subnet.ip_version + dnsNameServers: + source: subnet.dns_nameservers + cidr: + source: subnet.cidr + hostRoutes: + source: subnet.host_routes diff --git a/azure/multicloud_azure/api_v2/api_definition/utils.py b/azure/multicloud_azure/api_v2/api_definition/utils.py new file mode 100644 index 0000000..3f5a8a1 --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_definition/utils.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pkg_resources +import yaml + + +def get_definition_list(): + """ Get API Definition from YAML files. """ + + api_def = [] + definition_dir = __name__[:__name__.rfind(".")] + for f in pkg_resources.resource_listdir(definition_dir, '.'): + if f.endswith(".yaml"): + with pkg_resources.resource_stream(definition_dir, f) as fd: + # TODO(xiaohhui): Should add exception handler to inform user + # of potential error. + api_def.append(yaml.safe_load(fd)) + + return api_def diff --git a/azure/multicloud_azure/api_v2/api_router/__init__.py b/azure/multicloud_azure/api_v2/api_router/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/api_v2/api_router/root.py b/azure/multicloud_azure/api_v2/api_router/root.py new file mode 100644 index 0000000..76c42fd --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_router/root.py @@ -0,0 +1,34 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pecan +from pecan import rest + +from multicloud_azure.api_v2.api_router import v0_controller + + +class AzureController(rest.RestController): + v0 = v0_controller.V0_Controller() + + +class APIController(rest.RestController): + pass + + +# Pecan workaround for the dash in path. +pecan.route(APIController, "multicloud-azure", AzureController()) + + +class RootController(object): + api = APIController() diff --git a/azure/multicloud_azure/api_v2/api_router/swagger_json.py b/azure/multicloud_azure/api_v2/api_router/swagger_json.py new file mode 100644 index 0000000..ca6aa0b --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_router/swagger_json.py @@ -0,0 +1,25 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pecan +from pecan import rest + +from multicloud_azure.swagger import utils + + +class SwaggerJson(rest.RestController): + + @pecan.expose("json") + def get(self): + return utils.get_swagger_json_data() diff --git a/azure/multicloud_azure/api_v2/api_router/v0_controller.py b/azure/multicloud_azure/api_v2/api_router/v0_controller.py new file mode 100644 index 0000000..8d7e697 --- /dev/null +++ b/azure/multicloud_azure/api_v2/api_router/v0_controller.py @@ -0,0 +1,48 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pecan +from pecan import rest + +from multicloud_azure.api_v2.api_router import swagger_json + + +class V0_Controller(rest.RestController): + + def get(self, vim_id, tenant_id): + """ Placeholder for sub controllers. """ + pecan.abort(405) + + def put(self, vim_id, tenant_id): + """ Placeholder for sub controllers. """ + pecan.abort(405) + + def post(self, vim_id, tenant_id): + """ Placeholder for sub controllers. """ + pecan.abort(405) + + def delete(self, vim_id, tenant_id): + """ Placeholder for sub controllers. """ + pecan.abort(405) + + def get_all(self, vim_id, tenant_id): + """ Placeholder for sub controllers. """ + pecan.abort(405) + + +pecan.route(V0_Controller, "swagger.json", swagger_json.SwaggerJson()) + + +# Insert API stem from yaml files. +# controller_builder.insert_dynamic_controller(V0_Controller) diff --git a/azure/multicloud_azure/api_v2/app.py b/azure/multicloud_azure/api_v2/app.py new file mode 100644 index 0000000..2c13403 --- /dev/null +++ b/azure/multicloud_azure/api_v2/app.py @@ -0,0 +1,35 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pecan + + +def setup_app(config=None): + app_conf = { + 'root': "azure.api_v2.api_router.root.RootController", + 'modules': ["azure.api_v2"], + 'debug': True, + # NOTE: By default, guess_content_type_from_ext is True, and Pecan will + # strip the file extension from url. For example, ../../swagger.json + # will look like ../../swagger to Pecan API router. This makes other + # url like ../../swagger.txt get the same API route. Set this to False + # to do strict url mapping. + 'guess_content_type_from_ext': False + } + app = pecan.make_app( + app_conf.pop('root'), + **app_conf + ) + + return app diff --git a/azure/multicloud_azure/api_v2/service.py b/azure/multicloud_azure/api_v2/service.py new file mode 100644 index 0000000..d6e3923 --- /dev/null +++ b/azure/multicloud_azure/api_v2/service.py @@ -0,0 +1,54 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_concurrency import processutils +from oslo_config import cfg +from oslo_service import service +from oslo_service import wsgi + +from multicloud_azure.api_v2 import app +from multicloud_azure.pub.config import config as mc_cfg + + +CONF = cfg.CONF + + +class WSGIService(service.ServiceBase): + """Provides ability to launch API from wsgi app.""" + + def __init__(self): + self.app = app.setup_app() + + self.workers = processutils.get_worker_count() + + self.server = wsgi.Server( + CONF, + "azure", + self.app, + host="0.0.0.0", + port=mc_cfg.API_SERVER_PORT, + use_ssl=False + ) + + def start(self): + self.server.start() + + def stop(self): + self.server.stop() + + def wait(self): + self.server.wait() + + def reset(self): + self.server.reset() diff --git a/azure/multicloud_azure/event_listener/__init__.py b/azure/multicloud_azure/event_listener/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/event_listener/i18n.py b/azure/multicloud_azure/event_listener/i18n.py new file mode 100644 index 0000000..8fd9a6e --- /dev/null +++ b/azure/multicloud_azure/event_listener/i18n.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import oslo_i18n + +DOMAIN = "test_oslo" + +_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) + +# The primary translation function using the well-known name "_" +_ = _translators.primary + +# The contextual translation function using the name "_C" +_C = _translators.contextual_form + +# The plural translation function using the name "_P" +_P = _translators.plural_form + +# Translators for log levels. +# +# The abbreviated names are meant to reflect the usual use of a short +# name like '_'. The "L" is for "log" and the other letter comes from +# the level. +_LI = _translators.log_info +_LW = _translators.log_warning +_LE = _translators.log_error +_LC = _translators.log_critical diff --git a/azure/multicloud_azure/event_listener/listener.conf b/azure/multicloud_azure/event_listener/listener.conf new file mode 100644 index 0000000..4376fe7 --- /dev/null +++ b/azure/multicloud_azure/event_listener/listener.conf @@ -0,0 +1,15 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +[Listener] +rabbit_ip=10.154.9.172 +rabbit_passwd=6C2B96AsbinmFf1a9c6a \ No newline at end of file diff --git a/azure/multicloud_azure/event_listener/server.py b/azure/multicloud_azure/event_listener/server.py new file mode 100644 index 0000000..90e3461 --- /dev/null +++ b/azure/multicloud_azure/event_listener/server.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from oslo_config import cfg +from oslo_log import log as logging +from i18n import _LI +import oslo_messaging +import ConfigParser +import json +import os +import requests +from multicloud_azure.pub.config.config import MR_ADDR +from multicloud_azure.pub.config.config import MR_PORT + + +LOG = logging.getLogger(__name__) + + +def prepare(): + + product_name = "oslo_server" + logging.register_options(cfg.CONF) + logging.setup(cfg.CONF, product_name) + + +''' +below items must be added into vio nova.conf then restart nova services: +notification_driver=messaging +notification_topics= notifications_test +notify_on_state_change=vm_and_task_state +notify_on_any_change=True +instance_usage_audit=True +instance_usage_audit_period=hour +''' + + +def getConfig(section, key): + + config = ConfigParser.ConfigParser() + path = os.path.split(os.path.realpath(__file__))[0] + '/listener.conf' + config.read(path) + return config.get(section, key) + + +class NotificationEndPoint(): + + filter_rule = oslo_messaging.NotificationFilter( + publisher_id='^compute.*') + + def info(self, ctxt, publisher_id, event_type, payload, metadata): + + VM_EVENTS = { + 'compute.instance.unpause.start', + 'compute.instance.pause.start', + 'compute.instance.power_off.start', + 'compute.instance.reboot.start', + 'compute.instance.create.start' + } + + status = payload.get('state_description') + if status != '' and event_type in VM_EVENTS: + url = 'http://%s:%s/events/test' % (MR_ADDR, MR_PORT) + headers = {'Content-type': 'application/json'} + requests.post(url, json.dumps(payload), headers=headers) + + LOG.info(event_type) + self.action(payload) + + def action(self, data): + LOG.info(_LI(json.dumps(data))) + + +class Server(object): + + def __init__(self): + self.topic = 'notifications_test' + self.server = None + prepare() + + +class NotificationServer(Server): + + def __init__(self): + super(NotificationServer, self).__init__() + # rabbit IP and password come from listener.conf + url = 'rabbit://test:%s@%s:5672/' % ( + getConfig('Listener', 'rabbit_passwd'), + getConfig('Listener', 'rabbit_ip') + ) + self.transport = oslo_messaging.get_notification_transport( + cfg.CONF, + url=url) + # The exchange must be the same as + # control_exchange in transport setting in client. + self.targets = [oslo_messaging.Target( + topic=self.topic, + exchange='nova')] + self.endpoints = [NotificationEndPoint()] + + def start(self): + LOG.info(_LI("Start Notification server...")) + self.server = oslo_messaging.get_notification_listener( + self.transport, + self.targets, + self.endpoints, + executor='threading') + self.server.start() + self.server.wait() + + +if __name__ == '__main__': + + notification_server = NotificationServer() + notification_server.start() diff --git a/azure/multicloud_azure/middleware.py b/azure/multicloud_azure/middleware.py new file mode 100644 index 0000000..5b99e9a --- /dev/null +++ b/azure/multicloud_azure/middleware.py @@ -0,0 +1,59 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +import uuid +from onaplogging.mdcContext import MDC +from multicloud_azure.pub.config.config import SERVICE_NAME +from multicloud_azure.pub.config.config import FORWARDED_FOR_FIELDS + + +class LogContextMiddleware(object): + + # the last IP behind multiple proxies, if no exist proxies + # get local host ip. + def _getLastIp(self, request): + + ip = "" + try: + for field in FORWARDED_FOR_FIELDS: + if field in request.META: + if ',' in request.META[field]: + parts = request.META[field].split(',') + ip = parts[-1].strip().split(":")[0] + else: + ip = request.META[field].split(":")[0] + + if ip == "": + ip = request.META.get("HTTP_HOST").split(":")[0] + + except Exception: + pass + + return ip + + def process_request(self, request): + + ReqeustID = request.META.get("HTTP_X_TRANSACTIONID", None) + if ReqeustID is None: + ReqeustID = str(uuid.uuid3(uuid.NAMESPACE_URL, SERVICE_NAME)) + MDC.put("requestID", ReqeustID) + InovocationID = str(uuid.uuid4()) + MDC.put("invocationID", InovocationID) + MDC.put("serviceName", SERVICE_NAME) + MDC.put("serviceIP", self._getLastIp(request)) + return None + + def process_response(self, request, response): + + MDC.clear() + return response diff --git a/azure/multicloud_azure/pub/__init__.py b/azure/multicloud_azure/pub/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/config/__init__.py b/azure/multicloud_azure/pub/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/config/config.py b/azure/multicloud_azure/pub/config/config.py new file mode 100644 index 0000000..db09fd6 --- /dev/null +++ b/azure/multicloud_azure/pub/config/config.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import os + +# [MSB] +MSB_SERVICE_IP = "msb.onap.org" +MSB_SERVICE_PORT = "10080" + +# [IMAGE LOCAL PATH] +ROOT_PATH = os.path.dirname(os.path.dirname( + os.path.dirname(os.path.abspath(__file__)))) + +# [A&AI] +AAI_ADDR = "aai.api.simpledemo.openecomp.org" +AAI_PORT = "8443" +AAI_SERVICE_URL = 'https://%s:%s/aai' % (AAI_ADDR, AAI_PORT) +AAI_SCHEMA_VERSION = "v13" +AAI_USERNAME = "AAI" +AAI_PASSWORD = "AAI" + +# [DMaaP] +MR_ADDR = "" +MR_PORT = "" + +# [MDC] +SERVICE_NAME = "multicloud-azure" +FORWARDED_FOR_FIELDS = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST", + "HTTP_X_FORWARDED_SERVER"] + +# [Local Config] +API_SERVER_PORT = 9004 diff --git a/azure/multicloud_azure/pub/config/log.yml b/azure/multicloud_azure/pub/config/log.yml new file mode 100644 index 0000000..7bbc427 --- /dev/null +++ b/azure/multicloud_azure/pub/config/log.yml @@ -0,0 +1,26 @@ +version: 1 +disable_existing_loggers: False + +loggers: + azure: + handlers: [azure_handler] + level: "DEBUG" + propagate: False +handlers: + azure_handler: + level: "DEBUG" + class: "logging.handlers.RotatingFileHandler" + filename: "/var/log/onap/multicloud/azure/azure.log" + formatter: "mdcFormat" + maxBytes: 52428800 + backupCount: 10 +formatters: + standard: + format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s" + mdcFormat: + format: "%(asctime)s|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s \t" + mdcfmt: "{requestID} {invocationID} {serviceName} {serviceIP}" + datefmt: "%Y-%m-%d %H:%M:%S" + (): onaplogging.mdcformatter.MDCFormatter + + diff --git a/azure/multicloud_azure/pub/database/__init__.py b/azure/multicloud_azure/pub/database/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/database/models.py b/azure/multicloud_azure/pub/database/models.py new file mode 100644 index 0000000..757430b --- /dev/null +++ b/azure/multicloud_azure/pub/database/models.py @@ -0,0 +1,23 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from django.db import models + + +class VimInstModel(models.Model): + class Meta: + db_table = 'vim_inst_type_mapping' + + vimid = models.CharField( + db_column='VIMID', primary_key=True, max_length=200) + vimtype = models.CharField(db_column="VIMTYPE", max_length=200) + viminst_url = models.CharField(db_column="VIMINSTURL", max_length=200) diff --git a/azure/multicloud_azure/pub/exceptions.py b/azure/multicloud_azure/pub/exceptions.py new file mode 100644 index 0000000..3f38f2c --- /dev/null +++ b/azure/multicloud_azure/pub/exceptions.py @@ -0,0 +1,66 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +class ClientException(Exception): + + message = "ClientException" + + def __init__(self, message=None): + self.message = message or self.message + super(ClientException, self).__init__(self.message) + + +class ServerException(Exception): + + message = "ServerException" + + def __init__(self, message=None, status_code="", content=""): + super(ServerException, self).__init__(message) + self.message = message or self.message + self.status_code = status_code + self.content = content + + +class RetriableConnectionFailure(Exception): + pass + + +class ConnectionError(ClientException): + message = "Cannot connect to API service." + + +class ConnectTimeout(ConnectionError, RetriableConnectionFailure): + message = "Timed out connecting to service." + + +class ConnectFailure(ConnectionError, RetriableConnectionFailure): + message = "Connection failure that may be retried." + + +class SSLError(ConnectionError): + message = "An SSL error occurred." + + +class UnknownConnectionError(ConnectionError): + + def __init__(self, msg, original): + super(UnknownConnectionError, self).__init__(msg) + self.original = original + + +class NotFoundError(ServerException): + message = "Cannot find value" + + +class VimDriverAzureException(ServerException): + message = "Cannot find vim driver" diff --git a/azure/multicloud_azure/pub/msapi/__init__.py b/azure/multicloud_azure/pub/msapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/msapi/extsys.py b/azure/multicloud_azure/pub/msapi/extsys.py new file mode 100644 index 0000000..4d78337 --- /dev/null +++ b/azure/multicloud_azure/pub/msapi/extsys.py @@ -0,0 +1,47 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import logging + +from multicloud_azure.pub.utils.restcall import AAIClient + +logger = logging.getLogger(__name__) + + +def split_vim_to_owner_region(vim_id): + split_vim = vim_id.split('_') + cloud_owner = split_vim[0] + cloud_region = "".join(split_vim[1:]) + return cloud_owner, cloud_region + + +def get_vim_by_id(vim_id): + cloud_owner, cloud_region = split_vim_to_owner_region(vim_id) + client = AAIClient(cloud_owner, cloud_region) + ret = client.get_vim(get_all=True) + esrInfo = ret['esr-system-info-list']['esr-system-info'][0] + data = { + 'type': ret['cloud-type'], + 'version': ret['cloud-region-version'], + 'cloud_extra_info': ret['cloud-extra-info'], + 'cloud_region_id': ret['cloud-region-id'], + 'name': vim_id, + 'username': esrInfo['user-name'], + 'password': esrInfo['password'], + 'default_tenant': esrInfo['default-tenant'], + 'url': esrInfo['service-url'], + 'domain': esrInfo['cloud-domain'], + 'cacert': esrInfo.get('ssl-cacert', ""), + 'insecure': esrInfo.get('ssl-insecure', False) + } + ret.update(data) + return ret diff --git a/azure/multicloud_azure/pub/utils/__init__.py b/azure/multicloud_azure/pub/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/utils/enumutil.py b/azure/multicloud_azure/pub/utils/enumutil.py new file mode 100644 index 0000000..eb7a22c --- /dev/null +++ b/azure/multicloud_azure/pub/utils/enumutil.py @@ -0,0 +1,15 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +def enum(**enums): + return type('Enum', (), enums) diff --git a/azure/multicloud_azure/pub/utils/fileutil.py b/azure/multicloud_azure/pub/utils/fileutil.py new file mode 100644 index 0000000..1868300 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/fileutil.py @@ -0,0 +1,50 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +import os +import shutil +import logging +import traceback +import urllib2 + +logger = logging.getLogger(__name__) + + +def make_dirs(path): + if not os.path.exists(path): + os.makedirs(path, 0777) + + +def delete_dirs(path): + try: + if os.path.exists(path): + shutil.rmtree(path) + except Exception as e: + logger.error(traceback.format_exc()) + logger.error("Failed to delete %s:%s", path, e.message) + + +def download_file_from_http(url, local_dir, file_name): + local_file_name = os.path.join(local_dir, file_name) + is_download_ok = False + try: + make_dirs(local_dir) + r = urllib2.Request(url) + req = urllib2.urlopen(r) + save_file = open(local_file_name, 'wb') + save_file.write(req.read()) + save_file.close() + req.close() + is_download_ok = True + except Exception: + logger.error(traceback.format_exc()) + logger.error("Failed to download %s to %s.", url, local_file_name) + return is_download_ok, local_file_name diff --git a/azure/multicloud_azure/pub/utils/idutil.py b/azure/multicloud_azure/pub/utils/idutil.py new file mode 100644 index 0000000..be6e8a0 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/idutil.py @@ -0,0 +1,18 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +from redisco import containers as cont + + +def get_auto_id(id_type, id_group="auto_id_hash"): + auto_id_hash = cont.Hash(id_group) + auto_id_hash.hincrby(id_type, 1) + return auto_id_hash.hget(id_type) diff --git a/azure/multicloud_azure/pub/utils/restcall.py b/azure/multicloud_azure/pub/utils/restcall.py new file mode 100644 index 0000000..984c425 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/restcall.py @@ -0,0 +1,530 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import sys +import traceback +import logging +import urllib2 +import uuid +import httplib2 +import json + +from multicloud_azure.pub.config.config import AAI_SCHEMA_VERSION +from multicloud_azure.pub.config.config import AAI_SERVICE_URL +from multicloud_azure.pub.config.config import AAI_USERNAME +from multicloud_azure.pub.config.config import AAI_PASSWORD +from multicloud_azure.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT + +from multicloud_azure.pub.exceptions import VimDriverAzureException + +rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2 +HTTP_200_OK, HTTP_201_CREATED = '200', '201' +HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED = '204', '202' +status_ok_list = [HTTP_200_OK, HTTP_201_CREATED, + HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED] +HTTP_404_NOTFOUND, HTTP_403_FORBIDDEN = '404', '403' +HTTP_401_UNAUTHORIZED, HTTP_400_BADREQUEST = '401', '400' + +logger = logging.getLogger(__name__) + + +def call_req(base_url, user, passwd, auth_type, resource, method, content='', + headers=None): + callid = str(uuid.uuid1()) +# logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % ( +# callid, base_url, user, passwd, auth_type, resource, method, content)) + ret = None + resp_status = '' + resp = "" + full_url = "" + + try: + full_url = combine_url(base_url, resource) + if headers is None: + headers = {} + headers['content-type'] = 'application/json' + + if user: + headers['Authorization'] = 'Basic ' + \ + ('%s:%s' % (user, passwd)).encode("base64") + ca_certs = None + for retry_times in range(3): + http = httplib2.Http( + ca_certs=ca_certs, + disable_ssl_certificate_validation=( + auth_type == rest_no_auth)) + http.follow_all_redirects = True + try: + logger.debug("request=%s" % full_url) + resp, resp_content = http.request( + full_url, method=method.upper(), body=content, + headers=headers) + resp_status = resp['status'] + resp_body = resp_content.decode('UTF-8') + + if resp_status in status_ok_list: + ret = [0, resp_body, resp_status, resp] + else: + ret = [1, resp_body, resp_status, resp] + break + except Exception as ex: + if 'httplib.ResponseNotReady' in str(sys.exc_info()): + logger.error(traceback.format_exc()) + ret = [1, "Unable to connect to %s" % full_url, + resp_status, resp] + continue + raise ex + except urllib2.URLError as err: + ret = [2, str(err), resp_status, resp] + except Exception as ex: + logger.error(traceback.format_exc()) + logger.error("[%s]ret=%s" % (callid, str(sys.exc_info()))) + res_info = str(sys.exc_info()) + if 'httplib.ResponseNotReady' in res_info: + res_info = ("The URL[%s] request failed or is not responding." % + full_url) + ret = [3, res_info, resp_status, resp] +# logger.debug("[%s]ret=%s" % (callid, str(ret))) + return ret + + +def req_by_msb(resource, method, content=''): + base_url = "http://%s:%s/" % (MSB_SERVICE_IP, MSB_SERVICE_PORT) + return call_req(base_url, "", "", rest_no_auth, resource, method, content) + + +def combine_url(base_url, resource): + full_url = None + if base_url.endswith('/') and resource.startswith('/'): + full_url = base_url[:-1] + resource + elif base_url.endswith('/') and not resource.startswith('/'): + full_url = base_url + resource + elif not base_url.endswith('/') and resource.startswith('/'): + full_url = base_url + resource + else: + full_url = base_url + '/' + resource + return full_url + + +def get_res_from_aai(resource, content=''): + headers = { + 'X-FromAppId': 'MultiCloud', + 'X-TransactionId': '9001', + 'content-type': 'application/json', + 'accept': 'application/json' + } + base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) + return call_req(base_url, AAI_USERNAME, AAI_PASSWORD, rest_no_auth, + resource, "GET", content, headers) + + +class AAIClient(object): + def __init__(self, cloud_owner, cloud_region): + self.base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) + self.username = AAI_USERNAME + self.password = AAI_PASSWORD + self.default_headers = { + 'X-FromAppId': 'multicloud-azure', + 'X-TransactionId': '9004', + 'content-type': 'application/json', + 'accept': 'application/json' + } + self.cloud_owner = cloud_owner + self.cloud_region = cloud_region + self._vim_info = None + + def get_vim(self, get_all=False): + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s" % (self.cloud_owner, self.cloud_region)) + if get_all: + resource = "%s?depth=all" % resource + resp = call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "GET", + headers=self.default_headers) + if resp[0] != 0: + raise VimDriverAzureException( + status_code=404, + content="Failed to query VIM with id (%s_%s) from extsys." % ( + self.cloud_owner, self.cloud_region)) + return json.loads(resp[1]) + + def delete_vim(self): + resp = self.get_vim(get_all=True) + logger.debug('Delete cloud region') + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s?resource-version=%s" % + (self.cloud_owner, self.cloud_region, + resp['resource-version'])) + resp = call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "DELETE", + headers=self.default_headers) + if resp[0] != 0: + raise VimDriverAzureException( + status_code=400, + content="Failed to delete cloud %s_%s: %s." % ( + self.cloud_owner, self.cloud_region, resp[1])) + + def update_vim(self, content): + self.add_flavors(content) + + def update_identity_url(self): + vim = self.get_vim() + vim['identity-url'] = ("http://%s/api/multicloud/v0/%s_%s/identity/" + "v3" % (MSB_SERVICE_IP, self.cloud_owner, + self.cloud_region)) + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s" % (self.cloud_owner, self.cloud_region)) + logger.debug("Updating identity url %s" % vim) + call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "PUT", + content=json.dumps(vim), + headers=self.default_headers) + + def add_flavors(self, content): + for flavor in content['flavors']: + resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" + "%s/%s/flavors/flavor/%s" % ( + self.cloud_owner, self.cloud_region, + flavor['name'])) + body = { + 'flavor-name': flavor['name'], + 'flavor-vcpus': flavor['vcpus'], + 'flavor-ram': flavor['ram'], + 'flavor-disk': flavor['disk'], + 'flavor-selflink': "" + } + # Handle extra specs + if flavor['name'].startswith("onap."): + hpa_capabilities = self._get_hpa_capabilities( + flavor) + body['hpa-capabilities'] = { + 'hpa-capability': hpa_capabilities} + + logger.debug("Adding flavors to cloud region") + call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "PUT", + content=json.dumps(body), + headers=self.default_headers) + + def _get_hpa_capabilities(self, flavor): + hpa_caps = [] + + # Basic capabilties + caps_dict = self._get_hpa_basic_capabilities(flavor) + if len(caps_dict) > 0: + logger.debug("basic_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # cpupining capabilities + caps_dict = self._get_cpupinning_capabilities(flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("cpupining_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # cputopology capabilities + caps_dict = self._get_cputopology_capabilities(flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("cputopology_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # hugepages capabilities + caps_dict = self._get_hugepages_capabilities(flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("hugepages_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # numa capabilities + caps_dict = self._get_numa_capabilities(flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("numa_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # storage capabilities + caps_dict = self._get_storage_capabilities(flavor) + if len(caps_dict) > 0: + logger.debug("storage_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # CPU instruction set extension capabilities + caps_dict = self._get_instruction_set_capabilities( + flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("instruction_set_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # PCI passthrough capabilities + caps_dict = self._get_pci_passthrough_capabilities( + flavor['extra_specs']) + if len(caps_dict) > 0: + logger.debug("pci_passthrough_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + # ovsdpdk capabilities + caps_dict = self._get_ovsdpdk_capabilities() + if len(caps_dict) > 0: + logger.debug("ovsdpdk_capabilities_info: %s" % caps_dict) + hpa_caps.append(caps_dict) + + return hpa_caps + + def _get_hpa_basic_capabilities(self, flavor): + basic_capability = {} + feature_uuid = uuid.uuid4() + + basic_capability['hpa-capability-id'] = str(feature_uuid) + basic_capability['hpa-feature'] = 'basicCapabilities' + basic_capability['architecture'] = 'generic' + basic_capability['hpa-version'] = 'v1' + + basic_capability['hpa-feature-attributes'] = [] + basic_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'numVirtualCpu', + 'hpa-attribute-value': json.dumps( + {'value': str(flavor['vcpus'])})}) + basic_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'virtualMemSize', + 'hpa-attribute-value': json.dumps({'value': str( + flavor['ram']), 'unit': 'GB'})}) + + return basic_capability + + def _get_cpupinning_capabilities(self, extra_specs): + cpupining_capability = {} + feature_uuid = uuid.uuid4() + + if (extra_specs.get('hw:cpu_policy') or + extra_specs.get('hw:cpu_thread_policy')): + cpupining_capability['hpa-capability-id'] = str(feature_uuid) + cpupining_capability['hpa-feature'] = 'cpuPinning' + cpupining_capability['architecture'] = 'generic' + cpupining_capability['hpa-version'] = 'v1' + + cpupining_capability['hpa-feature-attributes'] = [] + if extra_specs.get('hw:cpu_thread_policy'): + cpupining_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'logicalCpuThreadPinningPolicy', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:cpu_thread_policy'])})}) + if extra_specs.get('hw:cpu_policy'): + cpupining_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'logicalCpuPinningPolicy', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:cpu_policy'])})}) + + return cpupining_capability + + def _get_cputopology_capabilities(self, extra_specs): + cputopology_capability = {} + feature_uuid = uuid.uuid4() + + if (extra_specs.get('hw:cpu_sockets') or + extra_specs.get('hw:cpu_cores') or + extra_specs.get('hw:cpu_threads')): + cputopology_capability['hpa-capability-id'] = str(feature_uuid) + cputopology_capability['hpa-feature'] = 'cpuTopology' + cputopology_capability['architecture'] = 'generic' + cputopology_capability['hpa-version'] = 'v1' + + cputopology_capability['hpa-feature-attributes'] = [] + if extra_specs.get('hw:cpu_sockets'): + cputopology_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'numCpuSockets', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:cpu_sockets'])})}) + if extra_specs.get('hw:cpu_cores'): + cputopology_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'numCpuCores', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:cpu_cores'])})}) + if extra_specs.get('hw:cpu_threads'): + cputopology_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'numCpuThreads', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:cpu_threads'])})}) + + return cputopology_capability + + def _get_hugepages_capabilities(self, extra_specs): + hugepages_capability = {} + feature_uuid = uuid.uuid4() + + if extra_specs.get('hw:mem_page_size'): + hugepages_capability['hpa-capability-id'] = str(feature_uuid) + hugepages_capability['hpa-feature'] = 'hugePages' + hugepages_capability['architecture'] = 'generic' + hugepages_capability['hpa-version'] = 'v1' + + hugepages_capability['hpa-feature-attributes'] = [] + if extra_specs['hw:mem_page_size'] == 'large': + hugepages_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'memoryPageSize', + 'hpa-attribute-value': json.dumps( + {'value': '2', 'unit': 'MB'})}) + elif extra_specs['hw:mem_page_size'] == 'small': + hugepages_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'memoryPageSize', + 'hpa-attribute-value': json.dumps( + {'value': '4', 'unit': 'KB'})}) + elif extra_specs['hw:mem_page_size'] == 'any': + logger.info("Currently HPA feature memoryPageSize " + "did not support 'any' page!!") + else: + hugepages_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'memoryPageSize', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:mem_page_size']), 'unit': 'KB'}) + }) + + return hugepages_capability + + def _get_numa_capabilities(self, extra_specs): + numa_capability = {} + feature_uuid = uuid.uuid4() + + if extra_specs.get('hw:numa_nodes'): + numa_capability['hpa-capability-id'] = str(feature_uuid) + numa_capability['hpa-feature'] = 'numa' + numa_capability['architecture'] = 'generic' + numa_capability['hpa-version'] = 'v1' + + numa_capability['hpa-feature-attributes'] = [] + numa_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'numaNodes', + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs['hw:numa_nodes'])}) + }) + + for num in range(0, int(extra_specs['hw:numa_nodes'])): + numa_cpu_node = "hw:numa_cpus.%s" % num + numa_mem_node = "hw:numa_mem.%s" % num + numacpu_key = "numaCpu-%s" % num + numamem_key = "numaMem-%s" % num + + if (extra_specs.get(numa_cpu_node) and + extra_specs.get(numa_mem_node)): + numa_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': numacpu_key, + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs[numa_cpu_node])}) + }) + numa_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': numamem_key, + 'hpa-attribute-value': json.dumps({'value': str( + extra_specs[numa_mem_node]), 'unit': 'MB'}) + }) + + return numa_capability + + def _get_storage_capabilities(self, flavor): + storage_capability = {} + feature_uuid = uuid.uuid4() + + storage_capability['hpa-capability-id'] = str(feature_uuid) + storage_capability['hpa-feature'] = 'localStorage' + storage_capability['architecture'] = 'generic' + storage_capability['hpa-version'] = 'v1' + + storage_capability['hpa-feature-attributes'] = [] + storage_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'diskSize', + 'hpa-attribute-value': json.dumps({'value': str( + flavor['disk']), 'unit': 'MB'}) + }) + storage_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'swapMemSize', + 'hpa-attribute-value': json.dumps({'value': str( + flavor.get('swap', 0)), 'unit': 'MB'}) + }) + storage_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'ephemeralDiskSize', + 'hpa-attribute-value': json.dumps({'value': str( + flavor.get('OS-FLV-EXT-DATA:ephemeral', 0)), 'unit': 'GB'}) + }) + return storage_capability + + def _get_instruction_set_capabilities(self, extra_specs): + instruction_capability = {} + feature_uuid = uuid.uuid4() + + if extra_specs.get('hw:capabilities:cpu_info:features'): + instruction_capability['hpa-capability-id'] = str(feature_uuid) + instruction_capability['hpa-feature'] = 'instructionSetExtensions' + instruction_capability['architecture'] = 'Intel64' + instruction_capability['hpa-version'] = 'v1' + + instruction_capability['hpa-feature-attributes'] = [] + instruction_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'instructionSetExtensions', + 'hpa-attribute-value': json.dumps( + {'value': extra_specs[ + 'hw:capabilities:cpu_info:features']}) + }) + return instruction_capability + + def _get_pci_passthrough_capabilities(self, extra_specs): + instruction_capability = {} + feature_uuid = uuid.uuid4() + + if extra_specs.get('pci_passthrough:alias'): + value1 = extra_specs['pci_passthrough:alias'].split(':') + value2 = value1[0].split('-') + + instruction_capability['hpa-capability-id'] = str(feature_uuid) + instruction_capability['hpa-feature'] = 'pciePassthrough' + instruction_capability['architecture'] = str(value2[2]) + instruction_capability['hpa-version'] = 'v1' + + instruction_capability['hpa-feature-attributes'] = [] + instruction_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'pciCount', + 'hpa-attribute-value': json.dumps({'value': value1[1]}) + }) + instruction_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'pciVendorId', + 'hpa-attribute-value': json.dumps({'value': value2[3]}) + }) + instruction_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': 'pciDeviceId', + 'hpa-attribute-value': json.dumps({'value': value2[4]}) + }) + + return instruction_capability + + def _get_ovsdpdk_capabilities(self): + ovsdpdk_capability = {} + feature_uuid = uuid.uuid4() + + if not self._vim_info: + self._vim_info = self.get_vim(get_all=True) + cloud_extra_info_str = self._vim_info.get('cloud-extra-info') + if not isinstance(cloud_extra_info_str, dict): + try: + cloud_extra_info_str = json.loads(cloud_extra_info_str) + except Exception as ex: + logger.error("Can not convert cloud extra info %s %s" % ( + str(ex), cloud_extra_info_str)) + return {} + if cloud_extra_info_str: + cloud_dpdk_info = cloud_extra_info_str.get("ovsDpdk") + if cloud_dpdk_info: + ovsdpdk_capability['hpa-capability-id'] = str(feature_uuid) + ovsdpdk_capability['hpa-feature'] = 'ovsDpdk' + ovsdpdk_capability['architecture'] = 'Intel64' + ovsdpdk_capability['hpa-version'] = 'v1' + + ovsdpdk_capability['hpa-feature-attributes'] = [] + ovsdpdk_capability['hpa-feature-attributes'].append({ + 'hpa-attribute-key': str(cloud_dpdk_info.get("libname")), + 'hpa-attribute-value': json.dumps( + {'value': cloud_dpdk_info.get("libversion")}) + }) + return ovsdpdk_capability diff --git a/azure/multicloud_azure/pub/utils/syscomm.py b/azure/multicloud_azure/pub/utils/syscomm.py new file mode 100644 index 0000000..f838956 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/syscomm.py @@ -0,0 +1,111 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import inspect +import json +from collections import defaultdict +from rest_framework import status + + +keystoneV2Json = \ + { + "auth": { + "tenantName": "", + "passwordCredentials": { + "username": "", + "password": "" + } + } + } + + +SUCCESS_STATE = [status.HTTP_200_OK, status.HTTP_201_CREATED, + status.HTTP_202_ACCEPTED] + + +def fun_name(): + return inspect.stack()[1][3] + + +def jsonResponse(data, encoding='utf-8'): + + content_type = "application/json" + try: + res = json.loads(data, encoding=encoding) + except Exception: + res = data + content_type = "text/plain" + return (res, content_type) + + +class Catalogs(object): + + def __init__(self): + self.ct = defaultdict(dict) + + def storeEndpoint(self, vimid, endpoints): + if vimid in self.ct: + self.ct[vimid].update(endpoints) + else: + self.ct.setdefault(vimid, endpoints) + + def getEndpointBy(self, vimid, serverType, interface='public'): + + vim = self.ct.get(vimid) + return vim.get(serverType).get(interface, "") if vim else "" + + +def verifyKeystoneV2(param): + + return _walk_json(param, keystoneV2Json) + + +# comapare two json by key +def _walk_json(data, data2): + if isinstance(data, dict) and isinstance(data2, dict): + if set(data.keys()) != set(data2.keys()): + return False + else: + v1 = data.values() + v2 = data2.values() + v1.sort() + v2.sort() + if len(v1) != len(v2): + return False + for (i, j) in zip(v1, v2): + # continue compare key + if isinstance(i, dict) and isinstance(j, dict): + if not _walk_json(i, j): + return False + # ignore value + else: + continue + + return True + + return False + + +def keystoneVersion(url, version="v3"): + + tmp = url.split("/") + v = tmp[-1] + if v not in ["v2.0", "v3"]: + url += "/" + version + else: + tmp[-1] = version + url = "/".join(tmp) + + return url + + +catalog = Catalogs() diff --git a/azure/multicloud_azure/pub/utils/timeutil.py b/azure/multicloud_azure/pub/utils/timeutil.py new file mode 100644 index 0000000..d5ef329 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/timeutil.py @@ -0,0 +1,17 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import datetime + + +def now_time(fmt="%Y-%m-%d %H:%M:%S"): + return datetime.datetime.now().strftime(fmt) diff --git a/azure/multicloud_azure/pub/utils/values.py b/azure/multicloud_azure/pub/utils/values.py new file mode 100644 index 0000000..61d7114 --- /dev/null +++ b/azure/multicloud_azure/pub/utils/values.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +def ignore_case_get(args, key, def_val=""): + if not key: + return def_val + if key in args: + return args[key] + for old_key in args: + if old_key.upper() == key.upper(): + return args[old_key] + return def_val diff --git a/azure/multicloud_azure/pub/vim/__init__.py b/azure/multicloud_azure/pub/vim/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/vim/const.py b/azure/multicloud_azure/pub/vim/const.py new file mode 100644 index 0000000..dc5a3a4 --- /dev/null +++ b/azure/multicloud_azure/pub/vim/const.py @@ -0,0 +1,14 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +SAMPLE_KEY = "sample_value" diff --git a/azure/multicloud_azure/pub/vim/vimapi/__init__.py b/azure/multicloud_azure/pub/vim/vimapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/vim/vimapi/baseclient.py b/azure/multicloud_azure/pub/vim/vimapi/baseclient.py new file mode 100644 index 0000000..4a9844b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/baseclient.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import logging + +from multicloud_azure.pub.vim.vimsdk.azure_credentials import ClientObj +from azure.mgmt.compute import ComputeManagementClient +from azure.mgmt.resource import ResourceManagementClient + +LOG = logging.getLogger(__name__) + + +class baseclient(object): + + def __init__(self, **kwargs): + self._compute = None + self._resource = None + + def get_compute_client(self, params): + if self._compute is not None: + return self._compute + credentials = ClientObj().get_client_obj(params) + self._compute = ComputeManagementClient( + credentials, params['subscription_id']) + return self._compute + + def get_resource_client(self, params): + if self._resource is not None: + return self._resource + credentials = ClientObj.get_client_obj(params) + self._resource = ResourceManagementClient( + credentials, params['subscription_id']) + return self._resource diff --git a/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py new file mode 100644 index 0000000..799a0d1 --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import logging + +from multicloud_azure.pub.vim.vimapi.baseclient import baseclient + + +logger = logging.getLogger(__name__) + + +class OperateCompute(baseclient): + + def __init__(self, **kwargs): + super(OperateCompute, self).__init__(**kwargs) + + def request(self, op, data, **kwargs): + compute = self.get_compute_client(data) + func = getattr(compute, op) + return func diff --git a/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py new file mode 100644 index 0000000..827366b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import logging + +from OperateCompute import OperateCompute +from multicloud_azure.swagger import compute_utils +logger = logging.getLogger(__name__) + + +class OperateFlavors(OperateCompute): + + def __init__(self, **kwargs): + super(OperateFlavors, self).__init__(**kwargs) + + def list_flavors(self, data, **query): + logger.info("Inside OperateFlavors.list_flavors ") + flavors = self.request('virtual_machine_sizes', data, **query) + flavors = flavors.list(data['region_id']) + vmSizes = [] + for flavor in flavors: + result = compute_utils.convert_vmsize_aai(flavor) + vmSizes.append(result) + return vmSizes diff --git a/azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py b/azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/vim/vimsdk/__init__.py b/azure/multicloud_azure/pub/vim/vimsdk/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py b/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py new file mode 100644 index 0000000..e66ac7b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py @@ -0,0 +1,28 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from azure.common.credentials import ServicePrincipalCredentials + + +class ClientObj(object): + + def get_client_obj(self, params): + if params is None: + params = {} + TENANT_ID = params['tenant_id'] + CLIENT = params['username'] + KEY = params['password'] + + credentials = ServicePrincipalCredentials(client_id=CLIENT, + secret=KEY, tenant=TENANT_ID) + + return credentials diff --git a/azure/multicloud_azure/pub/vim/vimsdk/sdk.py b/azure/multicloud_azure/pub/vim/vimsdk/sdk.py new file mode 100644 index 0000000..c716620 --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimsdk/sdk.py @@ -0,0 +1,20 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from multicloud_azure.pub.vim.vimapi.baseclient import baseclient + + +def create_connection(params): + if params is None: + params = {} + client = baseclient.get_compute_client(params) + return client diff --git a/azure/multicloud_azure/samples/__init__.py b/azure/multicloud_azure/samples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/samples/tests.py b/azure/multicloud_azure/samples/tests.py new file mode 100644 index 0000000..e801e48 --- /dev/null +++ b/azure/multicloud_azure/samples/tests.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import unittest +import json +from django.test import Client +from rest_framework import status + + +class SampleViewTest(unittest.TestCase): + def setUp(self): + self.client = Client() + + def tearDown(self): + pass + + def test_sample(self): + response = self.client.get("/samples/") + self.assertEqual(status.HTTP_200_OK, + response.status_code, response.content) + resp_data = json.loads(response.content) + self.assertEqual("active", resp_data["status"]) diff --git a/azure/multicloud_azure/samples/urls.py b/azure/multicloud_azure/samples/urls.py new file mode 100644 index 0000000..3c10ace --- /dev/null +++ b/azure/multicloud_azure/samples/urls.py @@ -0,0 +1,17 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from django.conf.urls import url +from multicloud_azure.samples import views + +urlpatterns = [ + url(r'^samples/$', views.SampleList.as_view()), ] diff --git a/azure/multicloud_azure/samples/views.py b/azure/multicloud_azure/samples/views.py new file mode 100644 index 0000000..6576450 --- /dev/null +++ b/azure/multicloud_azure/samples/views.py @@ -0,0 +1,35 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import os +import logging + +from rest_framework.views import APIView +from rest_framework.response import Response + +logger = logging.getLogger(__name__) +log_file = "/var/log/onap/multicloud/azure/azure.log" + + +class SampleList(APIView): + """ + List all samples. + """ + + def get(self, request, format=None): + logger.debug("get") + output = "" + if os.path.exists(log_file): + with open("/var/log/onap/multicloud/azure/azure.log", "r") as f: + lines = f.readlines() + output = lines[-1] + return Response({"status": "active", "logs": output}) diff --git a/azure/multicloud_azure/scripts/__init__.py b/azure/multicloud_azure/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/scripts/api.py b/azure/multicloud_azure/scripts/api.py new file mode 100644 index 0000000..b516ca8 --- /dev/null +++ b/azure/multicloud_azure/scripts/api.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import eventlet +eventlet.monkey_patch() + +import os # noqa +from oslo_config import cfg # noqa +from oslo_service import service # noqa +import sys # noqa +# FIXME: Since there is no explicitly setup process for the project. Hack the +# python here. +sys.path.append(os.path.abspath('.')) + +from multicloud_azure.api_v2 import service as api_service # noqa + + +def main(): + try: + api_server = api_service.WSGIService() + launcher = service.launch(cfg.CONF, + api_server, + workers=api_server.workers) + launcher.wait() + except RuntimeError as excp: + sys.stderr.write("ERROR: %s\n" % excp) + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/azure/multicloud_azure/settings-cover.py b/azure/multicloud_azure/settings-cover.py new file mode 100644 index 0000000..0c1316a --- /dev/null +++ b/azure/multicloud_azure/settings-cover.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from multicloud_azure.settings import * # noqa +from multicloud_azure.settings import INSTALLED_APPS + +INSTALLED_APPS.append('django_nose') + +TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' + +NOSE_ARGS = [ + '--with-coverage', + '--cover-package=multicloud_azure', +] diff --git a/azure/multicloud_azure/settings.py b/azure/multicloud_azure/settings.py new file mode 100644 index 0000000..5078754 --- /dev/null +++ b/azure/multicloud_azure/settings.py @@ -0,0 +1,98 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import os +import sys +from logging import config +from onaplogging import monkey +monkey.patch_all() + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '3o-wney!99y)^h3v)0$j16l9=fdjxcb+a8g+q3tfbahcnu2b0o' + +# SECURITY WARNING: don't run with debug turned on in production! +# DEBUG = True + +ALLOWED_HOSTS = ['*'] + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'multicloud_azure.pub.database', +] + +MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'multicloud_azure.middleware.LogContextMiddleware', +] + +ROOT_URLCONF = 'multicloud_azure.urls' + +WSGI_APPLICATION = 'multicloud_azure.wsgi.application' + +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': ( + 'rest_framework.renderers.JSONRenderer', + ), + + 'DEFAULT_PARSER_CLASSES': ( + 'rest_framework.parsers.JSONParser', + 'rest_framework.parsers.MultiPartParser', + # 'rest_framework.parsers.FormParser', + # 'rest_framework.parsers.FileUploadParser', + ) +} + + +TIME_ZONE = 'UTC' + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.6/howto/static-files/ + +STATIC_URL = '/static/' + + +LOGGING_CONFIG = None +# yaml configuration of logging +LOGGING_FILE = os.path.join(BASE_DIR, 'multicloud_azure/pub/config/log.yml') +config.yamlConfig(filepath=LOGGING_FILE, watchDog=True) + + +if 'test' in sys.argv: + from multicloud_azure.pub.config import config + REST_FRAMEWORK = {} + import platform + + if platform.system() == 'Linux': + TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' + TEST_OUTPUT_VERBOSE = True + TEST_OUTPUT_DESCRIPTIONS = True + TEST_OUTPUT_DIR = 'test-reports' diff --git a/azure/multicloud_azure/swagger/__init__.py b/azure/multicloud_azure/swagger/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/compute_utils.py b/azure/multicloud_azure/swagger/compute_utils.py new file mode 100644 index 0000000..53bd587 --- /dev/null +++ b/azure/multicloud_azure/swagger/compute_utils.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import six + + +def extra_specs_formatter(extra_specs): + return [{"keyName": k, "value": v} + for k, v in six.iteritems(extra_specs.extra_specs)] + + +def convert_vmsize_aai(vmsize): + + body = { + 'name': vmsize.name, + 'vcpus': vmsize.number_of_cores, + 'disk': vmsize.os_disk_size_in_mb, + 'ram': vmsize.memory_in_mb + } + return body diff --git a/azure/multicloud_azure/swagger/image_utils.py b/azure/multicloud_azure/swagger/image_utils.py new file mode 100644 index 0000000..a17565e --- /dev/null +++ b/azure/multicloud_azure/swagger/image_utils.py @@ -0,0 +1,65 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +def image_formatter(image): + + image = image.to_dict() + properties = {} + if image.get("vmware_adaptertype"): + properties['vmware_adaptertype'] = image.get("vmware_adaptertype") + if image.get("vmware_ostype"): + properties['vmware_ostype'] = image.get("vmware_ostype") + + return { + 'id': image.get("id"), + 'name': image.get("name"), + 'imageType': image.get("disk_format"), + 'status': image.get("status"), + 'size': image.get("size"), + 'containerFormat': image.get("container_format"), + 'visibility': image.get("visibility"), + 'properties': properties + } + + +def vim_formatter(vim_info, tenantid): + + rsp = {} + rsp['vimId'] = vim_info.get('vimId') + rsp['vimName'] = vim_info.get('name') + rsp['tenantId'] = tenantid + return rsp + + +def sdk_param_formatter(data): + + param = {} + param['username'] = data.get('userName') + param['password'] = data.get('password') + param['auth_url'] = data.get('url') + param['project_id'] = data.get('tenant') + param['user_domain_name'] = 'default' + param['project_domain_name'] = 'default' + return param + + +def req_body_formatter(body): + + param = {} + param['name'] = body.get('name') + param['disk_format'] = body.get('imageType') + param['container_format'] = body.get('containerFormat') + param['visibility'] = body.get('visibility') + properties = body.get('properties', {}) + param.update(properties) + return param diff --git a/azure/multicloud_azure/swagger/multivim.flavor.swagger.json b/azure/multicloud_azure/swagger/multivim.flavor.swagger.json new file mode 100644 index 0000000..76e53f4 --- /dev/null +++ b/azure/multicloud_azure/swagger/multivim.flavor.swagger.json @@ -0,0 +1,365 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "MultiVIM Service rest API" + }, + "basePath": "/api/multicloud_azure/v0/", + "tags": [ + { + "name": "MultiVIM Azure services" + } + ], + "paths": { + "/{vimid}/flavors": { + "post": { + "tags": [ + "vim flavors" + ], + "summary": "create a flavor", + "description": "create a flavor", + "operationId": "create_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "create vim flavor request param", + "required": true, + "schema": { + "$ref": "#/definitions/CreateVimFlavor" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query vim flavors list", + "description": "query vim flavors list", + "operationId": "query_vim_flavors", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "get a list of vim flavors request param", + "required": false, + "schema": { + "$ref": "#/definitions/ListVimFlavors" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorsInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + }, + "/{vimid}/flavors/{flavorid}": { + "delete": { + "tags": [ + "vim flavors" + ], + "summary": "delete specific vim flavor", + "description": "delete specific vim flavor", + "operationId": "delete_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "successful operation" + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query specific vim flavor", + "description": "query specific vim flavor", + "operationId": "query_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + } + }, + "definitions": { + "CreateVimFlavor": { + "type": "object", + "required": [ + "vcpu", + "name", + "memory", + "disk" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + } + } + }, + "VimFlavorExtraSpecInfo": { + "type": "object", + "properties": { + "keyName": { + "type": "string", + "description": "extra spec key" + }, + "value": { + "type": "string", + "description": "extra spec value" + } + } + }, + "ListVimFlavors": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "flavor name to filter flavor list" + }, + "limit": { + "type": "integer", + "description": "Requests a page size of items" + }, + "marker": { + "type": "string", + "description": "flavor ID of the last-seen item" + } + } + }, + "VimFlavorsInfo": { + "type": "object", + "required": [ + "vimId", + "tenantId", + "flavors" + ], + "properties": { + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "flavors": { + "type": "array", + "description": "flavor list information", + "items": { + "$ref": "#/definitions/VimFlavorInfo" + } + } + } + }, + "VimFlavorInfo": { + "type": "object", + "required": [ + "name", + "id", + "vcpu", + "memory", + "disk", + "ephemeral", + "swap", + "isPublic" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "id": { + "type": "string", + "description": "flavor UUID" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + }, + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "tenantId": { + "type": "string", + "description": "tenant UUID" + }, + "returnCode": { + "type": "integer", + "description": "0: Already exist 1: Newly created" + } + } + } + } +} diff --git a/azure/multicloud_azure/swagger/tests.py b/azure/multicloud_azure/swagger/tests.py new file mode 100644 index 0000000..4631455 --- /dev/null +++ b/azure/multicloud_azure/swagger/tests.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import unittest +# import json +from django.test import Client +from rest_framework import status + + +class SampleViewTest(unittest.TestCase): + def setUp(self): + self.client = Client() + + def tearDown(self): + pass + + def test_sample(self): + response = self.client.get("/api/multicloud-azure/v0/swagger.json") + self.assertEqual(status.HTTP_200_OK, + response.status_code, response.content) +# resp_data = json.loads(response.content) +# self.assertEqual({"status": "active"}, resp_data) diff --git a/azure/multicloud_azure/swagger/urls.py b/azure/multicloud_azure/swagger/urls.py new file mode 100644 index 0000000..6acd327 --- /dev/null +++ b/azure/multicloud_azure/swagger/urls.py @@ -0,0 +1,37 @@ +# Copyright (c) 2018 Amdocs +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from django.conf.urls import url +from rest_framework.urlpatterns import format_suffix_patterns + +from multicloud_azure.swagger.views.swagger_json import SwaggerJsonView + + +# Registry +from multicloud_azure.swagger.views.registry.views import Registry +from multicloud_azure.swagger.views.registry.views import UnRegistry + + +urlpatterns = [ + # swagger + url(r'^api/multicloud-azure/v0/swagger.json$', SwaggerJsonView.as_view()), + + # Registry + url(r'^api/multicloud-azure/v0/(?P[0-9a-z-A-Z\-\_]+)/registry$', + Registry.as_view()), + url(r'^api/multicloud-azure/v0/(?P[0-9a-z-A-Z\-\_]+)$', + UnRegistry.as_view()), + +] + +urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/azure/multicloud_azure/swagger/utils.py b/azure/multicloud_azure/swagger/utils.py new file mode 100644 index 0000000..cb7e4f0 --- /dev/null +++ b/azure/multicloud_azure/swagger/utils.py @@ -0,0 +1,37 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os + + +def get_swagger_json_data(): + json_file = os.path.join(os.path.dirname( + __file__), 'multivim.flavor.swagger.json') + f = open(json_file) + json_data = json.JSONDecoder().decode(f.read()) + f.close() + # json_file = os.path.join(os.path.dirname( + # __file__), 'multivim.image.swagger.json') + # f = open(json_file) + # json_data_temp = json.JSONDecoder().decode(f.read()) + # f.close() + # json_data["paths"].update(json_data_temp["paths"]) + # json_data["definitions"].update(json_data_temp["definitions"]) + + json_data["basePath"] = "/api/multicloud-azure/v0/" + json_data["info"]["title"] = "MultiVIM driver \ + of Microsoft Azure Service NBI" + + return json_data diff --git a/azure/multicloud_azure/swagger/views.py b/azure/multicloud_azure/swagger/views.py new file mode 100644 index 0000000..d6ea65c --- /dev/null +++ b/azure/multicloud_azure/swagger/views.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import logging +# import traceback + +# from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +# from multicloud_azure.pub.exceptions import VimDriverAzureException +from multicloud_azure.swagger import utils + +logger = logging.getLogger(__name__) + + +class SwaggerJsonView(APIView): + def get(self, request): + + return Response(utils.get_swagger_json_data()) diff --git a/azure/multicloud_azure/swagger/views/__init__.py b/azure/multicloud_azure/swagger/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/flavor/__init__.py b/azure/multicloud_azure/swagger/views/flavor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/flavor/views.py b/azure/multicloud_azure/swagger/views/flavor/views.py new file mode 100644 index 0000000..c4eb060 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/flavor/views.py @@ -0,0 +1,98 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import json + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors +from multicloud_azure.swagger import compute_utils +from multicloud_azure.pub.exceptions import VimDriverAzureException + + +class FlavorsView(APIView): + + def post(self, request, vimid): + try: + create_req = json.loads(request.body) + except Exception as e: + return Response(data={'error': 'Fail to decode request body.'}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + + data = {'subscription_id': vim_info['cloud_extra_info'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud_region']} + rsp = {'vimId': vim_info['cloud_extra_info'], + 'vimName': vim_info['name']} + flavor_name = create_req.get('name', None) + flavor_id = create_req.get('id', None) + flavors_op = OperateFlavors.OperateFlavors() + try: + target = flavor_id or flavor_name + flavor = flavors_op.find_flavor(data, target) + if flavor: + flavor, extra_specs = flavors_op.get_flavor( + data, flavor.id) + rsp['returnCode'] = 0 + else: + rsp['returnCode'] = 1 + flavor, extra_specs = flavors_op.create_flavor( + data, create_req) + flavor_dict = compute_utils.flavor_formatter(flavor, extra_specs) + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + rsp.update(flavor_dict) + return Response(data=rsp, status=status.HTTP_200_OK) + + def get(self, request, vimid): + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + + data = {'subscription_id': vim_info['cloud_extra_info'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud_region_id']} + query = dict(request.query_params) + flavors_op = OperateFlavors.OperateFlavors() + try: + flavors_result = flavors_op.list_flavors(data, **query) + flavors_dict = [compute_utils.flavor_formatter(flavor, extra) + for flavor, extra in flavors_result] + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + rsp = {'vimId': vim_info['cloud_extra_info'], + 'vimName': vim_info['name'], + 'flavors': flavors_dict} + + return Response(data=rsp, status=status.HTTP_200_OK) diff --git a/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json b/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json new file mode 100644 index 0000000..76e53f4 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json @@ -0,0 +1,365 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "MultiVIM Service rest API" + }, + "basePath": "/api/multicloud_azure/v0/", + "tags": [ + { + "name": "MultiVIM Azure services" + } + ], + "paths": { + "/{vimid}/flavors": { + "post": { + "tags": [ + "vim flavors" + ], + "summary": "create a flavor", + "description": "create a flavor", + "operationId": "create_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "create vim flavor request param", + "required": true, + "schema": { + "$ref": "#/definitions/CreateVimFlavor" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query vim flavors list", + "description": "query vim flavors list", + "operationId": "query_vim_flavors", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "get a list of vim flavors request param", + "required": false, + "schema": { + "$ref": "#/definitions/ListVimFlavors" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorsInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + }, + "/{vimid}/flavors/{flavorid}": { + "delete": { + "tags": [ + "vim flavors" + ], + "summary": "delete specific vim flavor", + "description": "delete specific vim flavor", + "operationId": "delete_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "successful operation" + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query specific vim flavor", + "description": "query specific vim flavor", + "operationId": "query_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + } + }, + "definitions": { + "CreateVimFlavor": { + "type": "object", + "required": [ + "vcpu", + "name", + "memory", + "disk" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + } + } + }, + "VimFlavorExtraSpecInfo": { + "type": "object", + "properties": { + "keyName": { + "type": "string", + "description": "extra spec key" + }, + "value": { + "type": "string", + "description": "extra spec value" + } + } + }, + "ListVimFlavors": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "flavor name to filter flavor list" + }, + "limit": { + "type": "integer", + "description": "Requests a page size of items" + }, + "marker": { + "type": "string", + "description": "flavor ID of the last-seen item" + } + } + }, + "VimFlavorsInfo": { + "type": "object", + "required": [ + "vimId", + "tenantId", + "flavors" + ], + "properties": { + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "flavors": { + "type": "array", + "description": "flavor list information", + "items": { + "$ref": "#/definitions/VimFlavorInfo" + } + } + } + }, + "VimFlavorInfo": { + "type": "object", + "required": [ + "name", + "id", + "vcpu", + "memory", + "disk", + "ephemeral", + "swap", + "isPublic" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "id": { + "type": "string", + "description": "flavor UUID" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + }, + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "tenantId": { + "type": "string", + "description": "tenant UUID" + }, + "returnCode": { + "type": "integer", + "description": "0: Already exist 1: Newly created" + } + } + } + } +} diff --git a/azure/multicloud_azure/swagger/views/multivim.swagger.json b/azure/multicloud_azure/swagger/views/multivim.swagger.json new file mode 100644 index 0000000..de3419f --- /dev/null +++ b/azure/multicloud_azure/swagger/views/multivim.swagger.json @@ -0,0 +1,51 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "MultiVIM Service rest API" + }, + "basePath": "/api/multicloud-azure/v0/", + "tags": [ + { + "name": "MultiVIM Azure services" + } + ], + "paths": { + "/{vimid}/registry": { + "post": { + "tags": [ + "vim registration" + ], + "summary": "vim registration API", + "description": "vim registration API", + "operationId": "vim_registration", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation" + }, + "404": { + "description": "the vim id is wrong" + }, + "500": { + "description": "error occured during the process" + } + } + } + } + } +} diff --git a/azure/multicloud_azure/swagger/views/registry/__init__.py b/azure/multicloud_azure/swagger/views/registry/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/registry/views.py b/azure/multicloud_azure/swagger/views/registry/views.py new file mode 100644 index 0000000..8464ce4 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/registry/views.py @@ -0,0 +1,87 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +import logging +import json + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from multicloud_azure.pub.exceptions import VimDriverAzureException +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.utils.restcall import AAIClient +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors + + +logger = logging.getLogger(__name__) + + +class Registry(APIView): + def _get_flavors(self, auth_info): + flavors_op = OperateFlavors.OperateFlavors() + try: + flavors = flavors_op.list_flavors(auth_info) + except Exception as e: + logger.exception("get flavors error %(e)s", {"e": e}) + raise e + + rsp = {"flavors": flavors} + return rsp + + def post(self, request, vimid): + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + cloud_extra_info = json.loads(vim_info['cloud_extra_info']) + data = { + 'subscription_id': cloud_extra_info['subscription_id'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud-region-id'] + } + rsp = {} + try: + logger.debug('Getting flavors') + flavors = self._get_flavors(data) + rsp.update(flavors) + # update A&AI + logger.debug('Put data into A&AI') + cloud_owner, cloud_region = extsys.split_vim_to_owner_region( + vimid) + aai_adapter = AAIClient(cloud_owner, cloud_region) + aai_adapter.update_vim(rsp) + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + return Response(data="", status=status.HTTP_200_OK) + + +class UnRegistry(APIView): + + def delete(self, request, vimid): + try: + cloud_owner, cloud_region = extsys.split_vim_to_owner_region( + vimid) + aai_adapter = AAIClient(cloud_owner, cloud_region) + aai_adapter.delete_vim() + except Exception as e: + return Response(data=e.message, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(data="", status=status.HTTP_204_NO_CONTENT) diff --git a/azure/multicloud_azure/swagger/views/swagger_json.py b/azure/multicloud_azure/swagger/views/swagger_json.py new file mode 100644 index 0000000..91c00dd --- /dev/null +++ b/azure/multicloud_azure/swagger/views/swagger_json.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +import json +import logging +import os + +from rest_framework.response import Response +from rest_framework.views import APIView + + +logger = logging.getLogger(__name__) + + +class SwaggerJsonView(APIView): + def get(self, request): + json_file = os.path.join(os.path.dirname( + __file__), 'multivim.swagger.json') + f = open(json_file) + json_data = json.JSONDecoder().decode(f.read()) + f.close() + # json_file = os.path.join(os.path.dirname( + # __file__), 'multivim.image.swagger.json') + # f = open(json_file) + # json_data_temp = json.JSONDecoder().decode(f.read()) + # f.close() + # json_data["paths"].update(json_data_temp["paths"]) + # json_data["definitions"].update(json_data_temp["definitions"]) + json_data["basePath"] = "/api/multicloud-azure/v0/" + json_data["info"]["title"] = "MultiVIM \ + driver of Microsoft Azure Service NBI" + return Response(json_data) diff --git a/azure/multicloud_azure/swagger/volume_utils.py b/azure/multicloud_azure/swagger/volume_utils.py new file mode 100644 index 0000000..ae11285 --- /dev/null +++ b/azure/multicloud_azure/swagger/volume_utils.py @@ -0,0 +1,72 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +def volume_formatter(volume): + + attachments = [] + for attach in volume.attachments: + vim_attach = { + 'device': attach['device'], + 'volumeId': attach['volume_id'], + 'hostName': attach['host_name'], + 'Id': attach['attachment_id'], + 'serverId': attach['server_id'] + } + attachments.append(vim_attach) + + return { + 'id': volume.id, + 'name': volume.name, + 'createTime': volume.created_at, + 'status': volume.status, + 'type': volume.volume_type, + 'size': volume.size, + 'availabilityZone': volume.availability_zone, + 'attachments': attachments + } + + +def vim_formatter(vim_info, tenantid): + + rsp = {} + rsp['vimId'] = vim_info.get('vimId') + rsp['vimName'] = vim_info.get('name') + rsp['tenantId'] = tenantid + return rsp + + +def sdk_param_formatter(data): + + param = {} + param['username'] = data.get('userName') + param['password'] = data.get('password') + param['auth_url'] = data.get('url') + param['project_id'] = data.get('tenant') + param['user_domain_name'] = 'default' + param['project_domain_name'] = 'default' + return param + + +def req_body_formatter(body): + + param = {} + param['name'] = body.get('name') + param['size'] = body.get('volumeSize') + + if body.get('volumeType'): + param['volume_type'] = body.get('volumeType') + if body.get('availabilityZone'): + param['availability_zone'] = body.get('availabilityZone') + if body.get('imageId'): + param['image_id'] = body.get('imageId') + return param diff --git a/azure/multicloud_azure/tests/__init__.py b/azure/multicloud_azure/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/tests/test_aai_client.py b/azure/multicloud_azure/tests/test_aai_client.py new file mode 100644 index 0000000..c782bd9 --- /dev/null +++ b/azure/multicloud_azure/tests/test_aai_client.py @@ -0,0 +1,77 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest + +from multicloud_azure.pub.utils import restcall + + +class TestAAIClient(unittest.TestCase): + + def setUp(self): + self.view = restcall.AAIClient("vmware", "4.0") + + @mock.patch.object(restcall, "call_req") + def test_get_vim(self, mock_call): + mock_call.return_value = [0, '{"cloudOwner": "vmware"}'] + ret = self.view.get_vim(get_all=True) + expect_ret = {"cloudOwner": "vmware"} + self.assertEqual(expect_ret, ret) + + @mock.patch.object(restcall.AAIClient, "get_vim") + @mock.patch.object(restcall, "call_req") + def test_update_identity_url(self, mock_call, mock_getvim): + mock_getvim.return_value = {} + self.view.update_identity_url() + mock_call.assert_called_once() + + @mock.patch.object(restcall, "call_req") + def test_add_flavors(self, mock_call): + flavors = { + "flavors": [{ + "name": "m1.small", + "id": "1", + "vcpus": 1, + "ram": 512, + "disk": 10, + "ephemeral": 0, + "swap": 0, + "is_public": True, + "links": [{"href": "http://fake-url"}], + "is_disabled": False + }] + } + self.view.add_flavors(flavors) + mock_call.assert_called_once() + + @mock.patch.object(restcall, "call_req") + def test_add_flavors_with_hpa(self, mock_call): + flavors = { + "flavors": [{ + "name": "onap.small", + "id": "1", + "vcpus": 1, + "ram": 512, + "disk": 10, + "ephemeral": 0, + "swap": 0, + "is_public": True, + "links": [{"href": "http://fake-url"}], + "is_disabled": False, + "extra_specs": {}, + }] + } + self.view._get_ovsdpdk_capabilities = mock.MagicMock() + self.view._get_ovsdpdk_capabilities.return_value = {} + self.view.add_flavors(flavors) + mock_call.assert_called_once() diff --git a/azure/multicloud_azure/tests/test_flavor_view.py b/azure/multicloud_azure/tests/test_flavor_view.py new file mode 100644 index 0000000..d946ece --- /dev/null +++ b/azure/multicloud_azure/tests/test_flavor_view.py @@ -0,0 +1,76 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import unittest + +import mock +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors +from multicloud_azure.swagger import compute_utils +from multicloud_azure.swagger.views.flavor.views import FlavorsView +from rest_framework import status + +VIM_INFO = {'cloud_extra_info': 1, 'username': 'user1', + 'password': '1234', 'default_tenant': 't1', + 'cloud_region_id': 'r1'} + + +class FlavorViewTest(unittest.TestCase): + + def setUp(self): + self.fsv = FlavorsView() + + def tearDown(self): + pass + + @mock.patch.object(compute_utils, 'convert_vmsize_aai') + @mock.patch.object(OperateFlavors.OperateFlavors, 'list_flavors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_flavors_get_fail(self, mock_vim_info, + mock_flavors, mock_formatter): + mock_vim_info.return_value = VIM_INFO + + class Flavor: + def __init__(self, id, name): + self.id = id + self.name = name + f1 = Flavor(1, "f1") + f2 = Flavor(2, "f2") + flavors = [f1, f2] + mock_flavors.return_value = flavors + mock_formatter.return_value = flavors + + class Request: + def __init__(self, query_params): + self.query_params = query_params + req = Request({'k': 'v'}) + self.assertEqual( + status.HTTP_500_INTERNAL_SERVER_ERROR, + self.fsv.get(req, "vimid").status_code) + + def test_vmsize_aai(self): + expected = { + 'name': "abc", + 'vcpus': 1, + 'ram': 123, + 'disk': 1234 + } + + class VmSize: + def __init__(self, name, number_of_cores, memory_in_mb, + os_disk_size_in_mb): + self.name = name + self.number_of_cores = number_of_cores + self.memory_in_mb = memory_in_mb + self.os_disk_size_in_mb = os_disk_size_in_mb + v1 = VmSize("abc", 1, 123, 1234) + self.assertEquals(expected, compute_utils.convert_vmsize_aai(v1)) diff --git a/azure/multicloud_azure/tests/test_restcall.py b/azure/multicloud_azure/tests/test_restcall.py new file mode 100644 index 0000000..9f60317 --- /dev/null +++ b/azure/multicloud_azure/tests/test_restcall.py @@ -0,0 +1,101 @@ +# Copyright (c) 2018 Amdocs +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest +import urllib2 + +from multicloud_azure.pub.utils import restcall + + +class TestRestCall(unittest.TestCase): + + def test_combine_url(self): + url = ["http://a.com/test/", "http://a.com/test/", + "http://a.com/test", "http://a.com/test"] + res = ["/resource", "resource", "/resource", "resource"] + expected = "http://a.com/test/resource" + for i in range(len(url)): + self.assertEqual(expected, restcall.combine_url(url[i], res[i])) + + @mock.patch.object(restcall, "call_req") + def test_get_res_from_aai(self, mock_call): + res = "cloud-regions" + content = "" + expect_url = "https://aai.api.simpledemo.openecomp.org:8443/aai/v13" + expect_user = "AAI" + expect_pass = "AAI" + expect_headers = { + 'X-FromAppId': 'MultiCloud', + 'X-TransactionId': '9001', + 'content-type': 'application/json', + 'accept': 'application/json' + } + restcall.get_res_from_aai(res, content=content) + mock_call.assert_called_once_with( + expect_url, expect_user, expect_pass, restcall.rest_no_auth, + res, "GET", content, expect_headers) + + @mock.patch.object(restcall, "call_req") + def test_req_by_msb(self, mock_call): + res = "multicloud" + method = "GET" + content = "no content" + restcall.req_by_msb(res, method, content=content) + expect_url = "http://msb.onap.org:10080/" + mock_call.assert_called_once_with( + expect_url, "", "", restcall.rest_no_auth, res, method, + content) + + @mock.patch("httplib2.Http.request") + def test_call_req_success(self, mock_req): + mock_resp = { + "status": "200" + } + resp_content = "hello" + mock_req.return_value = mock_resp, resp_content + expect_ret = [0, resp_content, "200", mock_resp] + ret = restcall.call_req("http://onap.org/", "user", "pass", + restcall.rest_no_auth, "vim", "GET") + self.assertEqual(expect_ret, ret) + + @mock.patch("httplib2.Http.request") + def test_call_req_not_200(self, mock_req): + mock_resp = { + "status": "404" + } + resp_content = "hello" + mock_req.return_value = mock_resp, resp_content + expect_ret = [1, resp_content, "404", mock_resp] + ret = restcall.call_req("http://onap.org/", "user", "pass", + restcall.rest_no_auth, "vim", "GET") + self.assertEqual(expect_ret, ret) + + @mock.patch("traceback.format_exc") + @mock.patch("sys.exc_info") + @mock.patch("httplib2.Http.request") + def test_call_req_response_not_ready(self, mock_req, mock_sys, + mock_traceback): + mock_sys.return_value = "httplib.ResponseNotReady" + mock_req.side_effect = [Exception("httplib.ResponseNotReady")] * 3 + expect_ret = [1, "Unable to connect to http://onap.org/vim", "", ""] + ret = restcall.call_req("http://onap.org/", "user", "pass", + restcall.rest_no_auth, "vim", "GET") + self.assertEqual(expect_ret, ret) + self.assertEqual(3, mock_req.call_count) + + @mock.patch("httplib2.Http.request") + def test_call_req_url_err(self, mock_req): + urlerr = urllib2.URLError("urlerror") + mock_req.side_effect = [urlerr] + expect_ret = [2, str(urlerr), "", ""] + ret = restcall.call_req("http://onap.org/", "user", "pass", + restcall.rest_no_auth, "vim", "GET") + self.assertEqual(expect_ret, ret) diff --git a/azure/multicloud_azure/tests/test_syscomm.py b/azure/multicloud_azure/tests/test_syscomm.py new file mode 100644 index 0000000..12507a4 --- /dev/null +++ b/azure/multicloud_azure/tests/test_syscomm.py @@ -0,0 +1,37 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import unittest + +from multicloud_azure.pub.utils import syscomm + + +class SyscommTest(unittest.TestCase): + + def test_keystone_version(self): + url = "http://a.com/test" + version = "v3" + expected = "http://a.com/test/v3" + self.assertEquals(expected, syscomm.keystoneVersion(url, version)) + + def test_verify_keystone(self): + param = \ + { + "auth": { + "tenantName": "12345", + "passwordCredentials": { + "username": "admin", + "password": "admin" + } + } + } + self.assertEquals(True, syscomm.verifyKeystoneV2(param)) diff --git a/azure/multicloud_azure/urls.py b/azure/multicloud_azure/urls.py new file mode 100644 index 0000000..bcc63b1 --- /dev/null +++ b/azure/multicloud_azure/urls.py @@ -0,0 +1,18 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from django.conf.urls import include, url + +urlpatterns = [ + url(r'^', include('multicloud_azure.swagger.urls')), + url(r'^', include('multicloud_azure.samples.urls')), +] diff --git a/azure/multicloud_azure/wsgi.py b/azure/multicloud_azure/wsgi.py new file mode 100644 index 0000000..f6f77d6 --- /dev/null +++ b/azure/multicloud_azure/wsgi.py @@ -0,0 +1,20 @@ +# Copyright (c) 2018 Amdocs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "multicloud_azure.settings") + +application = get_wsgi_application() diff --git a/azure/requirements.txt b/azure/requirements.txt index aa98578..f7225e9 100644 --- a/azure/requirements.txt +++ b/azure/requirements.txt @@ -37,3 +37,9 @@ oslo.config>=4.11.0 oslo.service>=1.25.0 eventlet>=0.20.0 PyYAML>=3.1.0 + +#azure +azure-mgmt-resource==2.0.0 +azure-mgmt-compute==4.0.1 +azure-mgmt-authorization==0.50.0 +azure-common==1.1.14 diff --git a/azure/run.sh b/azure/run.sh index 6883739..5ec19e2 100644 --- a/azure/run.sh +++ b/azure/run.sh @@ -31,8 +31,8 @@ then python multivimbroker/scripts/api.py else # nohup python manage.py runserver 0.0.0.0:9008 2>&1 & - nohup uwsgi --http :9008 --module azure.wsgi --master --processes 4 & - nohup python -m azure.event_listener.server 2>&1 & + nohup uwsgi --http :9008 --module multicloud_azure.wsgi --master --processes 4 & + nohup python -m multicloud_azure.event_listener.server 2>&1 & while [ ! -f $logDir/azure.log ]; do sleep 1 diff --git a/azure/setup.py b/azure/setup.py index c81e04f..92167ca 100644 --- a/azure/setup.py +++ b/azure/setup.py @@ -15,7 +15,7 @@ import setuptools setuptools.setup( - name="azure", + name="azure-plugin", version="1.0", packages=setuptools.find_packages(), include_package_data=True, diff --git a/azure/stop.sh b/azure/stop.sh index 04e822a..3c367de 100644 --- a/azure/stop.sh +++ b/azure/stop.sh @@ -12,4 +12,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # ps auxww | grep 'manage.py runserver 0.0.0.0:9004' | awk '{print $2}' | xargs kill -9 -ps auxww |grep 'uwsgi --http :9004 --module azure.wsgi --master' |awk '{print $2}' |xargs kill -9 +ps auxww |grep 'uwsgi --http :9004 --module multicloud_azure.wsgi --master' |awk '{print $2}' |xargs kill -9 diff --git a/azure/tox.ini b/azure/tox.ini index d6559ab..4c2c67e 100644 --- a/azure/tox.ini +++ b/azure/tox.ini @@ -9,7 +9,7 @@ downloadcache = ~/cache/pip deps = -r{toxinidir}/requirements.txt commands = /usr/bin/find . -type f -name "*.py[c|o]" -delete - python manage.py test azure + python manage.py test multicloud_azure [testenv:pep8] deps=flake8 @@ -21,7 +21,7 @@ commands = [testenv:cover] setenv= - DJANGO_SETTINGS_MODULE = azure.settings-cover + DJANGO_SETTINGS_MODULE = multicloud_azure.settings-cover commands = coverage erase {[testenv]commands} diff --git a/sonar.sh b/sonar.sh index 25cc44c..eee6415 100755 --- a/sonar.sh +++ b/sonar.sh @@ -58,7 +58,7 @@ run_tox_test() pip install --upgrade pip pip install --upgrade tox argparse pip freeze - cd azure + cd multicloud_azure tox -e cover deactivate cd .. -- cgit 1.2.3-korg