inmanta-module-openstack 5.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. inmanta_module_openstack-5.0.0/MANIFEST.in +5 -0
  2. inmanta_module_openstack-5.0.0/PKG-INFO +8 -0
  3. inmanta_module_openstack-5.0.0/README.md +261 -0
  4. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/PKG-INFO +8 -0
  5. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/SOURCES.txt +48 -0
  6. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/dependency_links.txt +1 -0
  7. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/not-zip-safe +1 -0
  8. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/requires.txt +4 -0
  9. inmanta_module_openstack-5.0.0/inmanta_module_openstack.egg-info/top_level.txt +1 -0
  10. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/__init__.py +186 -0
  11. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/common/__init__.py +17 -0
  12. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/common/base.py +327 -0
  13. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/common/deps.py +184 -0
  14. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/compute/__init__.py +17 -0
  15. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/compute/flavor.py +171 -0
  16. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/compute/host_port.py +296 -0
  17. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/compute/virtual_machine.py +313 -0
  18. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/__init__.py +17 -0
  19. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/group.py +91 -0
  20. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/group_role.py +184 -0
  21. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/keystone_base.py +71 -0
  22. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/project.py +102 -0
  23. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/role.py +189 -0
  24. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/identity/user.py +119 -0
  25. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/image/__init__.py +17 -0
  26. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/image/image.py +275 -0
  27. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/model/_init.cf +727 -0
  28. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/__init__.py +17 -0
  29. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/floating_ip.py +158 -0
  30. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/network.py +205 -0
  31. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/qos_policy.py +158 -0
  32. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/router.py +242 -0
  33. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/router_port.py +185 -0
  34. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/security_group.py +262 -0
  35. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/subnet.py +230 -0
  36. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/network/subnet_v6.py +241 -0
  37. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/quota/__init__.py +17 -0
  38. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/quota/quota.py +303 -0
  39. inmanta_module_openstack-5.0.0/inmanta_plugins/openstack/setup.cfg +42 -0
  40. inmanta_module_openstack-5.0.0/pyproject.toml +11 -0
  41. inmanta_module_openstack-5.0.0/setup.cfg +43 -0
  42. inmanta_module_openstack-5.0.0/tests/test_dependency_handling.py +170 -0
  43. inmanta_module_openstack-5.0.0/tests/test_examples.py +53 -0
  44. inmanta_module_openstack-5.0.0/tests/test_flavor.py +162 -0
  45. inmanta_module_openstack-5.0.0/tests/test_image.py +314 -0
  46. inmanta_module_openstack-5.0.0/tests/test_keystone.py +1049 -0
  47. inmanta_module_openstack-5.0.0/tests/test_neutron.py +1386 -0
  48. inmanta_module_openstack-5.0.0/tests/test_nova.py +230 -0
  49. inmanta_module_openstack-5.0.0/tests/test_quota.py +235 -0
@@ -0,0 +1,5 @@
1
+ include inmanta_plugins/openstack/setup.cfg
2
+ include inmanta_plugins/openstack/py.typed
3
+ recursive-include inmanta_plugins/openstack/model *.cf
4
+ graft inmanta_plugins/openstack/files
5
+ graft inmanta_plugins/openstack/templates
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: inmanta-module-openstack
3
+ Version: 5.0.0
4
+ License: Apache 2.0
5
+ Requires-Dist: inmanta-module-ssh
6
+ Requires-Dist: inmanta-module-std
7
+ Requires-Dist: python-dateutil<3,>=2.8
8
+ Requires-Dist: openstacksdk>=1.0
@@ -0,0 +1,261 @@
1
+ # openstack adapter
2
+
3
+ The openstack module provides support for managing various resources on OpenStack, including virtual
4
+ machines, networks, routers, ...
5
+
6
+ ## How to use it
7
+
8
+ This guide explains how to start virtual machines on OpenStack.More examples can be found in the `examples` folder of this repo.
9
+
10
+ ### Prerequisites
11
+
12
+ This tutorial requires you to have an account on an OpenStack. The example below loads the required
13
+ credentials from environment variables, just like the OpenStack command line tools. Additionally,
14
+ the following parameters are also required:
15
+
16
+ - **ssh_public_key** : Your public ssh key (the key itself, not the name of the file it is in)
17
+ - **network_name** : The name of the Openstack network to connect the VM to
18
+ - **subnet_name** : The name of the Openstack subnet to connect the VM to
19
+ - **network_address**: The network address of the subnet above
20
+ - **flavor_name** : The name of the Openstack flavor to create the VM from
21
+ - **image_id** : The ID of the Openstack image to boot the VM from
22
+ - **os** : The OS of the image
23
+
24
+ ### Creating machines
25
+
26
+ The following model creates a new virtual machine. The parameters in the list above are exposed as variables at the start of the code snippet.
27
+
28
+ ```inmanta
29
+ import openstack
30
+ import ssh
31
+
32
+ ## Edit this parameters
33
+ image_id = ""
34
+ network_name = ""
35
+ subnet_name = ""
36
+ network_address = ""
37
+
38
+ flavor_name = ""
39
+ ssh_public_key=""
40
+
41
+ # change OS parameter to match the actual image. If an OS is not modelled in an existing module,
42
+ # std::linux can be used for example. However, other modules might not have support for a
43
+ # generic os definition such as std::linux
44
+ os = std::linux
45
+ ## End edit
46
+
47
+ # register ssh key
48
+ ssh_key = ssh::Key(name="mykey", public_key=ssh_public_key)
49
+
50
+ # Define the OpenStack provider to use
51
+ provider = openstack::Provider(name="iaas_openstack", connection_url=std::get_env("OS_AUTH_URL"),
52
+ username=std::get_env("OS_USERNAME"),
53
+ password=std::get_env("OS_PASSWORD"),
54
+ project_name=std::get_env("OS_PROJECT_NAME"),
55
+ user_domain_name=std::gen_env("OS_USER_DOMAIN_NAME"),
56
+ project_domain_name=std::gen_env("OS_PROJECT_DOMAIN_NAME"))
57
+
58
+ # Define the project to boot the VM in, but do not let inmanta manage it
59
+ project = openstack::Project(provider=provider, name=provider.project_name, description="", enabled=true,
60
+ managed=false)
61
+
62
+ # Define the network objects to connect the virtual machine to but again, do not manage them
63
+ net = openstack::Network(provider=provider, project=project, name=network_name, managed=false)
64
+ subnet = openstack::Subnet(provider=provider, project=project, network=net, dhcp=true, managed=false,
65
+ name=subnet_name, network_address=network_address)
66
+
67
+ # Define the virtual machine
68
+ vm = openstack::Host(provider=provider, project=project, key_pair=ssh_key, name="testhost",
69
+ image=image_id, os=os, flavor=flavor_name, user_data="", subnet=subnet)
70
+ ```
71
+
72
+ ### Getting the agent on the machine
73
+
74
+ The user_data attribute of the :inmanta:entity:`openstack::VirtualMachine` entity can inject a shell script that is executed
75
+ at first boot of the virtual machine (through cloud-init). Below is an example script to install
76
+ the inmanta agent (from RPM) and let it connect back to the management server.
77
+
78
+ ```bash
79
+ #!/bin/bash
80
+
81
+ hostname {{ name }}
82
+
83
+ curl -1sLf \
84
+ 'https://packages.inmanta.com/public/oss-stable/setup.rpm.sh' \
85
+ | sudo -E bash
86
+
87
+ dnf install -y inmanta-oss-agent
88
+
89
+ cat > /etc/inmanta/agent.cfg <<EOF
90
+ [config]
91
+ heartbeat-interval = 60
92
+ fact-expire = 60
93
+ state-dir=/var/lib/inmanta
94
+ environment={{ env_id }}
95
+ agent-names=\$node-name
96
+ [agent_rest_transport]
97
+ port={{port}}
98
+ host={{env_server}}
99
+ EOF
100
+
101
+ systemctl start inmanta-agent
102
+ systemctl enable inmanta-agent
103
+
104
+ ```
105
+
106
+ ### Pushing resources to the machine
107
+
108
+ You can use adapters from std or other modules to manage resources on the machine. For example, we can create a config file in /tmp by adding the following lines to the model that created the virtual machine:
109
+
110
+ ```inmanta
111
+ #put a file on the machine
112
+ std::ConfigFile(host = host1, path="/tmp/test", content="I did it!")
113
+ ```
114
+
115
+ ### Actual usage
116
+
117
+ Creating instances of `openstack::Host`, as shown above requires many parameters and relations,
118
+ creating a model that is hard to read. Often, these parameters are all the same within a single
119
+ model. This means that Inmanta can encapsulate this complexity.
120
+
121
+ In a larger model, a new `Host` type can encapsulate all settings that are the same for all hosts.
122
+ Additionally, an entity that represents the `infrastructure` can hold shared configuration such as
123
+ the provider, monitoring, shared networks, global parameters,...)
124
+
125
+ For example (`full source here <https://github.com/inmanta/openstack/tree/master/examples/openstackclean>`_)
126
+
127
+ Applied to the example above the main file is reduced to:
128
+
129
+ ```inmanta
130
+ import mymodule
131
+ import ssh
132
+
133
+ ## Edit this parameters
134
+ image_id = ""
135
+ network_name = ""
136
+ subnet_name = ""
137
+ network_address = ""
138
+
139
+ flavor_name = ""
140
+ ssh_public_key=""
141
+
142
+ # change OS parameter to match the actual image. If an OS is not modelled in an existing module,
143
+ # std::linux can be used for example. However, other modules might not have support for a
144
+ # generic os definition such as std::linux
145
+ os = std::linux
146
+ ## End edit
147
+
148
+ # register ssh key
149
+ ssh_key = ssh::Key(name="mykey", public_key=ssh_public_key)
150
+
151
+ # create the cluster
152
+ cluster = mymodule::MyCluster(network_name=network_name, subnet_name=subnet_name,
153
+ image_id=image_id, flavor=flavor_name, key=ssh_key,
154
+ network_address=network_address, os=os)
155
+
156
+ # make a vm!
157
+ host1 = mymodule::MyHost(name="testhost", cluster=cluster)
158
+ ```
159
+
160
+ With the following module:
161
+
162
+ ```inmanta
163
+ import openstack
164
+ import ssh
165
+
166
+
167
+ entity MyCluster:
168
+ """
169
+ A cluster object that represents all shared config and infrastructure,
170
+ including connecting to OpenStack.
171
+ """
172
+ string network_name
173
+ string subnet_name
174
+ string network_address
175
+ string image_id
176
+ string flavor
177
+ end
178
+
179
+ #input: the ssh key for all VMs
180
+ MyCluster.key [1] -- ssh::Key
181
+
182
+ #input: the OS for all VMs
183
+ MyCluster.os [1] -- std::OS
184
+
185
+ #internal: objects needed to construct hosts
186
+ MyCluster.provider [1] -- openstack::Provider
187
+ MyCluster.project [1] -- openstack::Project
188
+ MyCluster.net [1] -- openstack::Network
189
+ MyCluster.subnet [1] -- openstack::Subnet
190
+
191
+ implementation connection for MyCluster:
192
+ # Define the OpenStack provider to use
193
+ self.provider = openstack::Provider(name="iaas_openstack",
194
+ connection_url=std::get_env("OS_AUTH_URL"),
195
+ username=std::get_env("OS_USERNAME"),
196
+ password=std::get_env("OS_PASSWORD"),
197
+ project_name=std::get_env("OS_PROJECT_NAME"),
198
+ user_domain_name=std::gen_env("OS_USER_DOMAIN_NAME"),
199
+ project_domain_name=std::gen_env("OS_PROJECT_DOMAIN_NAME")
200
+ )
201
+
202
+ # Define the project to boot the VM in, but do not let inmanta manage it
203
+ self.project = openstack::Project(provider=self.provider, name=self.provider.project_name,
204
+ description="", enabled=true, managed=false)
205
+
206
+ # Define the network objects to connect the virtual machine to but again, do not manage them
207
+ self.net = openstack::Network(provider=self.provider, project=self.project,
208
+ name=self.network_name, managed=false)
209
+ self.subnet = openstack::Subnet(provider=self.provider, project=self.project,
210
+ network=self.net, dhcp=true, name=self.subnet_name,
211
+ network_address=self.network_address, managed=false)
212
+ end
213
+
214
+ implement MyCluster using connection
215
+
216
+ #define our own host type
217
+ entity MyHost extends openstack::Host:
218
+ end
219
+
220
+ #input: the cluster object
221
+ MyCluster.hosts [0:] -- MyHost.cluster [1]
222
+
223
+ implementation myhost for MyHost:
224
+ #wire up all config for agent injection
225
+ env_name = std::environment_name()
226
+ env_id = std::environment()
227
+ env_server = std::environment_server()
228
+ port = std::server_port()
229
+
230
+ #wire up all config for vm creation
231
+ self.provider = cluster.provider
232
+ self.project = cluster.project
233
+ self.image = cluster.image_id
234
+ self.subnet = cluster.subnet
235
+ self.user_data = std::template("mymodule/user_data.tmpl")
236
+ self.key_pair = cluster.key
237
+ self.os = cluster.os
238
+ self.flavor = cluster.flavor
239
+ end
240
+
241
+ # use our implemenation
242
+ # and also the catchall std::hostDefaults
243
+ # and the openstackVM implementation that sets the ip and create the eth0 port
244
+ implement MyHost using myhost, std::hostDefaults, openstack::openstackVM, openstack::eth0Port
245
+ ```
246
+
247
+ If this were not an example, we would make the following changes:
248
+
249
+ - hardcode the ``image_id`` and ``os`` (and perhaps ``flavor``) into the defintion of ``myhost``.
250
+ - the parameters on top would be moved to either an lsm service or filled in directly into the constructor.
251
+ - use ``std::password`` to store passwords, to prevent accidential check-ins with passwords in the source
252
+
253
+
254
+
255
+
256
+
257
+ ```{toctree}
258
+ :maxdepth: 1
259
+ autodoc.rst
260
+ CHANGELOG.md
261
+ ```
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: inmanta-module-openstack
3
+ Version: 5.0.0
4
+ License: Apache 2.0
5
+ Requires-Dist: inmanta-module-ssh
6
+ Requires-Dist: inmanta-module-std
7
+ Requires-Dist: python-dateutil<3,>=2.8
8
+ Requires-Dist: openstacksdk>=1.0
@@ -0,0 +1,48 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ inmanta_module_openstack.egg-info/PKG-INFO
6
+ inmanta_module_openstack.egg-info/SOURCES.txt
7
+ inmanta_module_openstack.egg-info/dependency_links.txt
8
+ inmanta_module_openstack.egg-info/not-zip-safe
9
+ inmanta_module_openstack.egg-info/requires.txt
10
+ inmanta_module_openstack.egg-info/top_level.txt
11
+ inmanta_plugins/openstack/__init__.py
12
+ inmanta_plugins/openstack/setup.cfg
13
+ inmanta_plugins/openstack/common/__init__.py
14
+ inmanta_plugins/openstack/common/base.py
15
+ inmanta_plugins/openstack/common/deps.py
16
+ inmanta_plugins/openstack/compute/__init__.py
17
+ inmanta_plugins/openstack/compute/flavor.py
18
+ inmanta_plugins/openstack/compute/host_port.py
19
+ inmanta_plugins/openstack/compute/virtual_machine.py
20
+ inmanta_plugins/openstack/identity/__init__.py
21
+ inmanta_plugins/openstack/identity/group.py
22
+ inmanta_plugins/openstack/identity/group_role.py
23
+ inmanta_plugins/openstack/identity/keystone_base.py
24
+ inmanta_plugins/openstack/identity/project.py
25
+ inmanta_plugins/openstack/identity/role.py
26
+ inmanta_plugins/openstack/identity/user.py
27
+ inmanta_plugins/openstack/image/__init__.py
28
+ inmanta_plugins/openstack/image/image.py
29
+ inmanta_plugins/openstack/model/_init.cf
30
+ inmanta_plugins/openstack/network/__init__.py
31
+ inmanta_plugins/openstack/network/floating_ip.py
32
+ inmanta_plugins/openstack/network/network.py
33
+ inmanta_plugins/openstack/network/qos_policy.py
34
+ inmanta_plugins/openstack/network/router.py
35
+ inmanta_plugins/openstack/network/router_port.py
36
+ inmanta_plugins/openstack/network/security_group.py
37
+ inmanta_plugins/openstack/network/subnet.py
38
+ inmanta_plugins/openstack/network/subnet_v6.py
39
+ inmanta_plugins/openstack/quota/__init__.py
40
+ inmanta_plugins/openstack/quota/quota.py
41
+ tests/test_dependency_handling.py
42
+ tests/test_examples.py
43
+ tests/test_flavor.py
44
+ tests/test_image.py
45
+ tests/test_keystone.py
46
+ tests/test_neutron.py
47
+ tests/test_nova.py
48
+ tests/test_quota.py
@@ -0,0 +1,4 @@
1
+ inmanta-module-ssh
2
+ inmanta-module-std
3
+ python-dateutil<3,>=2.8
4
+ openstacksdk>=1.0
@@ -0,0 +1,186 @@
1
+ """
2
+ Copyright 2022 Inmanta
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+
16
+ Contact: code@inmanta.com
17
+ """
18
+
19
+ import datetime
20
+ import logging
21
+ import math
22
+ from typing import Optional
23
+
24
+ import keystoneauth1.exceptions
25
+ import openstack.connection
26
+ import openstack.exceptions
27
+ from inmanta.execute.util import Unknown
28
+ from inmanta.plugins import PluginException, plugin
29
+
30
+ IMAGES = {}
31
+ FIND_IMAGE_RESULT = {}
32
+
33
+ LOGGER = logging.getLogger(__name__)
34
+
35
+
36
+ @plugin
37
+ def find_image(
38
+ provider: "openstack::Provider", os: "std::OS", name: "string" = None
39
+ ) -> "string":
40
+ """
41
+ Search for an image that matches the given operating system. This plugin uses
42
+ the os_distro and os_version tags of an image and the name and version attributes of
43
+ the OS parameter.
44
+
45
+ If multiple images match, the most recent image is returned.
46
+
47
+ :param provider: The provider to query for an image
48
+ :param os: The operating system and version (using os_distro and os_version metadata)
49
+ :param name: An optional string that the image name should contain
50
+ """
51
+ ident = (provider.name, os.name.lower(), str(os.version).lower(), name)
52
+ if ident in FIND_IMAGE_RESULT:
53
+ return FIND_IMAGE_RESULT[ident]
54
+
55
+ conn = None
56
+ try:
57
+ if provider.name not in IMAGES:
58
+ conn = openstack.connection.Connection(
59
+ auth_url=provider.connection_url,
60
+ username=provider.username,
61
+ password=provider.password,
62
+ project_name=provider.project_name,
63
+ user_domain_name=provider.user_domain_name,
64
+ project_domain_name=provider.project_domain_name,
65
+ verify_cert=provider.verify_cert,
66
+ )
67
+ IMAGES[provider.name] = list(conn.image.images())
68
+
69
+ target_distro = os.name.lower()
70
+ target_version = str(os.version).lower()
71
+
72
+ newest_time = datetime.datetime(1900, 1, 1)
73
+ newest_image = None
74
+
75
+ for image in IMAGES[provider.name]:
76
+ if image.visibility != "public":
77
+ continue
78
+ if not image.name or (name and name not in image.name):
79
+ continue
80
+
81
+ os_distro = getattr(image, "os_distro", None)
82
+ os_version = getattr(image, "os_version", None)
83
+ if not os_distro or not os_version:
84
+ continue
85
+ if (
86
+ os_distro.lower() != target_distro
87
+ or os_version.lower() != target_version
88
+ ):
89
+ continue
90
+
91
+ try:
92
+ t = datetime.datetime.strptime(image.updated_at, "%Y-%m-%dT%H:%M:%SZ")
93
+ except Exception:
94
+ continue
95
+
96
+ if t > newest_time:
97
+ newest_time = t
98
+ newest_image = image
99
+
100
+ if newest_image is None:
101
+ raise Exception(f"No image found for os {os.name} and version {os.version}")
102
+
103
+ result = newest_image.id
104
+ FIND_IMAGE_RESULT[ident] = result
105
+ return result
106
+ except (
107
+ openstack.exceptions.SDKException,
108
+ keystoneauth1.exceptions.ClientException,
109
+ ) as exc:
110
+ LOGGER.warning("Failed to fetch images for provider %s: %s", provider.name, exc)
111
+ return Unknown(None)
112
+ finally:
113
+ if conn is not None:
114
+ conn.close()
115
+
116
+
117
+ FLAVORS = {}
118
+ FIND_FLAVOR_RESULT = {}
119
+
120
+
121
+ @plugin
122
+ def find_flavor(
123
+ provider: "openstack::Provider",
124
+ vcpus: "number",
125
+ ram: "number",
126
+ pinned: "bool" = False,
127
+ ) -> "string":
128
+ """
129
+ Find the flavor that matches the closest to the resources requested.
130
+
131
+ :param vcpus: The number of virtual cpus in the flavor
132
+ :param ram: The amount of ram in gigabyte
133
+ :param pinned: Wether the CPUs need to be pinned (#vcpu == #pcpu)
134
+ """
135
+ ident = (provider.name, vcpus, ram, pinned)
136
+ if ident in FIND_FLAVOR_RESULT:
137
+ return FIND_FLAVOR_RESULT[ident]
138
+
139
+ conn = None
140
+ try:
141
+ if provider.name not in FLAVORS:
142
+ conn = openstack.connection.Connection(
143
+ auth_url=provider.connection_url,
144
+ username=provider.username,
145
+ password=provider.password,
146
+ project_name=provider.project_name,
147
+ user_domain_name=provider.user_domain_name,
148
+ project_domain_name=provider.project_domain_name,
149
+ verify_cert=provider.verify_cert,
150
+ )
151
+ FLAVORS[provider.name] = list(conn.compute.flavors(get_extra_specs=True))
152
+
153
+ selected: tuple[float, Optional[openstack.compute.v2.flavor.Flavor]] = (
154
+ 1000000,
155
+ None,
156
+ )
157
+ for flavor in FLAVORS[provider.name]:
158
+ is_pinned = flavor.extra_specs.get("hw:cpu_policy") == "dedicated"
159
+ if is_pinned ^ pinned:
160
+ continue
161
+
162
+ d_cpu = flavor.vcpus - vcpus
163
+ d_ram = (flavor.ram / 1024) - ram
164
+ distance = math.sqrt(math.pow(d_cpu, 2) + math.pow(d_ram, 2))
165
+ if d_cpu >= 0 and d_ram >= 0 and distance < selected[0]:
166
+ selected = (distance, flavor)
167
+
168
+ if selected[1] is None:
169
+ raise PluginException(
170
+ "Couldn't find a flavor with at least %s %s CPUs and %s Gigabytes of RAM."
171
+ % (vcpus, "pinned" if pinned else "unpinned", ram)
172
+ )
173
+
174
+ FIND_FLAVOR_RESULT[ident] = selected[1].name
175
+ return selected[1].name
176
+ except (
177
+ openstack.exceptions.SDKException,
178
+ keystoneauth1.exceptions.ClientException,
179
+ ) as exc:
180
+ LOGGER.warning(
181
+ "Failed to fetch flavors for provider %s: %s", provider.name, exc
182
+ )
183
+ return Unknown(None)
184
+ finally:
185
+ if conn is not None:
186
+ conn.close()
@@ -0,0 +1,17 @@
1
+ """
2
+ Copyright 2022 Inmanta
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+
16
+ Contact: code@inmanta.com
17
+ """