Skip to content

Commit

Permalink
434 create an image ims (#437)
Browse files Browse the repository at this point in the history
434 create an image ims

Reviewed-by: Anton Sidelnikov
  • Loading branch information
RusselSand authored May 28, 2024
1 parent 5c7a068 commit ebd7a06
Show file tree
Hide file tree
Showing 22 changed files with 434 additions and 0 deletions.
1 change: 1 addition & 0 deletions .stestr.blacklist.functional
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ otcextensions.tests.functional.sdk.waf.v1.test_domain*
otcextensions.tests.functional.sdk.tms*
otcextensions.tests.functional.sdk.nat.v2.test_dnat*
otcextensions.tests.functional.osclient.kms*
otcextensions.tests.functional.sdk.ims*
20 changes: 20 additions & 0 deletions doc/source/sdk/proxies/ims.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
IMS API
=======

.. automodule:: otcextensions.sdk.ims.v2._proxy

The Image Management Service Class
----------------------------------

Image Management Service (IMS) high-level interface is
available through the ``ims`` member of a
:class:`~openstack.connection.Connection` object. The ``ims`` member
will only be added if the ``otcextensions.sdk.register_otc_extensions(conn)``
method is called.

Image Operations
^^^^^^^^^^^^^^^^^^^^^^^^^

.. autoclass:: otcextensions.sdk.ims.v2._proxy.Proxy
:noindex:
:members: create_image
1 change: 1 addition & 0 deletions doc/source/sdk/proxies/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Service Proxies
VPC Endpoint (VPCEP) <vpcep>
Web Application Firewall (WAF) <waf>
Tag Management Service (TMS) <tms>
Image Management Service (IMS) <ims>

.. _service-proxies:

Expand Down
8 changes: 8 additions & 0 deletions doc/source/sdk/resources/ims/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
IMS Resources
=============

.. toctree::
:maxdepth: 1

v2/image

13 changes: 13 additions & 0 deletions doc/source/sdk/resources/ims/v2/image.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
otcextensions.sdk.ims.v2.image
=====================================

.. automodule:: otcextensions.sdk.ims.v2.image

The Image Class
---------------

The ``Image`` class inherits from
:class:`~otcextensions.sdk.sdk_resource.Resource`.

.. autoclass:: otcextensions.sdk.ims.v2.image.Image
:members:
1 change: 1 addition & 0 deletions doc/source/sdk/resources/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Open Telekom Cloud Resources
VPC Endpoint (VPCEP) <vpcep/index>
Web Application Firewall (WAF) <waf/index>
Tag Management Service (TMS) <tms/index>
Image Management Service (IMS) <ims/index>

Every resource which is used within the proxy methods have own attributes.
Those attributes define the behavior of the resource which can be a cluster
Expand Down
Empty file added examples/ims/__init__.py
Empty file.
33 changes: 33 additions & 0 deletions examples/ims/create_image_from_obs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# 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.
"""
Create Image
"""

import openstack
from otcextensions import sdk

openstack.enable_logging(True)
conn = openstack.connect(cloud='otc')
sdk.register_otc_extensions(conn)
attrs = {
"name": "CentOS-7-x86_64-GenericCloud.qcow2",
"description": "Create an image from a file in an OBS bucket",
"image_url": "ims-extensions-test:CentOS-7-x86_64.qcow2",
"os_version": "CentOS 7.0 64bit",
"min_disk": 40,
"image_tags": [{"key": "key2", "value": "value2"},
{"key": "key1", "value": "value1"}]
}
result = conn.ims.create_image(**attrs)
print(result)
4 changes: 4 additions & 0 deletions otcextensions/sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@
'service_type': 'identity',
'replace_system': True
},
'ims': {
'service_type': 'ims',
'endpoint_service_type': 'image',
},
'kms': {
'service_type': 'kms',
'append_project_id': True,
Expand Down
Empty file.
153 changes: 153 additions & 0 deletions otcextensions/sdk/ims/ims_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# 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 warnings

from openstack import exceptions
from openstack import service_description

from otcextensions.sdk.ims.v2 import _proxy


class ImsService(service_description.ServiceDescription):
"""The IMS service."""

supported_versions = {
'2': _proxy.Proxy
}

def _make_proxy(self, instance):
"""Create a Proxy for the service in question.
:param instance:
The `openstack.connection.Connection` we're working with.
"""
config = instance.config
version_string = config.get_api_version('ims') or '2'
endpoint_override = config.get_endpoint(self.service_type)
ep = config.get_service_catalog().url_for(
service_type=self.service_type,
region_name=config.region_name)

epo = '%(base)s/v%(ver)s' % {
'base': ep,
'ver': version_string}

if epo and not endpoint_override:
endpoint_override = epo

if not version_string and len(self.supported_versions) == 1:
version_string = list(self.supported_versions)[0]

proxy_obj = None
if endpoint_override and version_string and self.supported_versions:
proxy_class = self.supported_versions.get(version_string[0])
if proxy_class:
proxy_obj = config.get_session_client(
self.service_type,
constructor=proxy_class,
)
proxy_obj.endpoint_override = endpoint_override
proxy_obj.additional_headers = {
'Content-Type': 'application/json'}
else:
warnings.warn(
"The configured version, {version} for service"
" {service_type} is not known or supported by"
" openstacksdk. The resulting Proxy object will only"
" have direct passthrough REST capabilities.".format(
version=version_string,
service_type=self.service_type),
category=exceptions.UnsupportedServiceVersion)
elif endpoint_override and self.supported_versions:
temp_adapter = config.get_session_client(
self.service_type
)
api_version = temp_adapter.get_endpoint_data().api_version
proxy_class = self.supported_versions.get(str(api_version[0]))
if proxy_class:
proxy_obj = config.get_session_client(
self.service_type,
constructor=proxy_class,
)
else:
warnings.warn(
"Service {service_type} has an endpoint override set"
" but the version discovered at that endpoint, {version}"
" is not supported by openstacksdk. The resulting Proxy"
" object will only have direct passthrough REST"
" capabilities.".format(
version=api_version,
service_type=self.service_type),
category=exceptions.UnsupportedServiceVersion)

if proxy_obj:
if getattr(proxy_obj, 'skip_discovery', False):
return proxy_obj

data = proxy_obj.get_endpoint_data()
if data.catalog_url != data.service_url:
ep_key = '{service_type}_endpoint_override'.format(
service_type=self.service_type)
config.config[ep_key] = data.service_url
proxy_obj = config.get_session_client(
self.service_type,
constructor=proxy_class,
)
return proxy_obj
version_kwargs = {}
if version_string:
version_kwargs['version'] = version_string
elif self.supported_versions:
supported_versions = sorted([
int(f) for f in self.supported_versions])
version_kwargs['min_version'] = str(supported_versions[0])
version_kwargs['max_version'] = '{version}.latest'.format(
version=str(supported_versions[-1]))

temp_adapter = config.get_session_client(
self.service_type,
allow_version_hack=True,
**version_kwargs
)
found_version = temp_adapter.get_api_major_version()
if found_version is None:
if version_kwargs:
raise exceptions.NotSupported(
"The {service_type} service for {cloud}:{region_name}"
" exists but does not have any supported versions.".format(
service_type=self.service_type,
cloud=instance.name,
region_name=instance.config.region_name))
else:
raise exceptions.NotSupported(
"The {service_type} service for {cloud}:{region_name}"
" exists but no version was discoverable.".format(
service_type=self.service_type,
cloud=instance.name,
region_name=instance.config.region_name))
proxy_class = self.supported_versions.get(str(found_version[0]))
if not proxy_class:
warnings.warn(
"Service {service_type} has no discoverable version."
" The resulting Proxy object will only have direct"
" passthrough REST capabilities.".format(
service_type=self.service_type),
category=exceptions.UnsupportedServiceVersion)
return temp_adapter
proxy_class = self.supported_versions.get(str(found_version[0]))
if proxy_class:
version_kwargs['constructor'] = proxy_class
return config.get_session_client(
self.service_type,
allow_version_hack=True,
**version_kwargs
)
Empty file.
25 changes: 25 additions & 0 deletions otcextensions/sdk/ims/v2/_proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 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 openstack import proxy
from otcextensions.sdk.ims.v2 import image as _image


class Proxy(proxy.Proxy):
skip_discovery = True

def create_image(self, **attrs):
"""Create a new image with attrs
:param dict attrs: Keyword arguments which will be used to create a
:class:`~otcextensions.sdk.ims.v2.image.Image`
"""
return self._create(_image.Image, **attrs)
44 changes: 44 additions & 0 deletions otcextensions/sdk/ims/v2/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# 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 openstack import resource


class Image(resource.Resource):
resource_key = 'image'
base_path = '/cloudimages/action'

allow_create = True
#: Method for creating a resource (POST, PUT)
create_method = "POST"

name = resource.Body('name')
description = resource.Body('description')
os_type = resource.Body('os_type')
os_version = resource.Body('os_version')
image_url = resource.Body('image_url')
min_disk = resource.Body('min_disk', type=int)
is_config = resource.Body('is_config', type=bool)
cmk_id = resource.Body('cmk_id')
type = resource.Body('type')
max_ram = resource.Body('max_ram', type=int)
min_ram = resource.Body('min_ram', type=int)
is_quick_import = resource.Body('is_quick_import', type=bool)
tags = resource.Body('tags', type=list)
image_tags = resource.Body('image_tags', type=list)
data_images = resource.Body('data_images', type=list)
job_id = resource.Body('job_id')

def create(self, session, prepend_key=False, base_path=None):
# Overriden here to override prepend_key default value
return super(Image, self).create(session, prepend_key, base_path)
Empty file.
Empty file.
37 changes: 37 additions & 0 deletions otcextensions/tests/functional/sdk/ims/v2/test_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 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 openstack import _log

from otcextensions.tests.functional import base

_logger = _log.setup_logging('openstack')


class TestImage(base.BaseFunctionalTest):

def setUp(self):
super(TestImage, self).setUp()
self.ims = self.conn.ims

def test_create_image(self):
attrs = {
"name": "CentOS-7-x86_64-GenericCloud.qcow2",
"description": "Create an image from a file in an OBS bucket",
"image_url": "ims-extensions-test:CentOS-7-GenericCloud.qcow2",
"os_version": "CentOS 7.0 64bit",
"min_disk": 40,
"image_tags": [{"key": "key2", "value": "value2"},
{"key": "key1", "value": "value1"}]
}
result = self.ims.create_image(**attrs)
self.assertNotEqual(result, None)
24 changes: 24 additions & 0 deletions otcextensions/tests/functional/sdk/ims/v2/test_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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 openstack import _log

from otcextensions.tests.functional import base

_logger = _log.setup_logging('openstack')


class TestService(base.BaseFunctionalTest):

def test_initialize(self):
client = self.conn.ims

self.assertIsNotNone(client)
Empty file.
Empty file.
Loading

0 comments on commit ebd7a06

Please sign in to comment.