Skip to content

Commit 4a51390

Browse files
authored
Merge pull request #2049 from micafer/blazar_support
Initial Blazar support #2048
2 parents 124c47d + 7f19a86 commit 4a51390

File tree

6 files changed

+288
-1
lines changed

6 files changed

+288
-1
lines changed

libcloud/compute/drivers/openstack.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ class OpenStackVolumeV3Connection(OpenStackBaseConnection):
114114
service_region = "RegionOne"
115115

116116

117+
class OpenStackReservationConnection(OpenStackBaseConnection):
118+
service_type = "reservation"
119+
service_name = "blazar"
120+
service_region = "RegionOne"
121+
122+
117123
class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
118124
"""
119125
Base OpenStack node driver. Should not be used directly.
@@ -2813,6 +2819,15 @@ def encode_data(self, data):
28132819
return json.dumps(data)
28142820

28152821

2822+
class OpenStack_2_ReservationConnection(OpenStackReservationConnection):
2823+
responseCls = OpenStack_1_1_Response
2824+
accept_format = "application/json"
2825+
default_content_type = "application/json; charset=UTF-8"
2826+
2827+
def encode_data(self, data):
2828+
return json.dumps(data)
2829+
2830+
28162831
class OpenStack_2_PortInterfaceState(Type):
28172832
"""
28182833
Standard states of OpenStack_2_PortInterfaceState
@@ -2873,6 +2888,10 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver):
28732888
volumev3_connection = None
28742889
volume_connection = None
28752890

2891+
# Connection to the Blazar reservation API
2892+
reservation_connectionCls = OpenStack_2_ReservationConnection
2893+
reservation_connection = None
2894+
28762895
type = Provider.OPENSTACK
28772896

28782897
features = {"create_node": ["generates_password"]}
@@ -2929,6 +2948,16 @@ def __init__(self, *args, **kwargs):
29292948
super().__init__(*args, **kwargs)
29302949
self.network_connection = self.connection
29312950

2951+
# We run the init once to get the Blazar API connection
2952+
# and put that on the object under self.reservation_connection.
2953+
if original_ex_force_base_url or kwargs.get("ex_force_reservation_url"):
2954+
kwargs["ex_force_base_url"] = str(
2955+
kwargs.pop("ex_force_reservation_url", original_ex_force_base_url)
2956+
)
2957+
self.connectionCls = self.reservation_connectionCls
2958+
super().__init__(*args, **kwargs)
2959+
self.reservation_connection = self.connection
2960+
29322961
# We run the init once again to get the compute API connection
29332962
# and that's put under self.connection as normal.
29342963
self._ex_force_base_url = original_ex_force_base_url
@@ -4368,6 +4397,100 @@ def ex_detach_floating_ip_from_node(self, node, ip):
43684397
)
43694398
return resp.status == httplib.OK
43704399

4400+
def ex_list_leases(self):
4401+
"""
4402+
List leases
4403+
4404+
:rtype: ``list`` of :class:`OpenStack_2_Lease`
4405+
"""
4406+
return self._to_leases(self.reservation_connection.request("/leases").object)
4407+
4408+
def _to_leases(self, obj):
4409+
lease_elements = obj["leases"]
4410+
return [self._to_lease(lease) for lease in lease_elements]
4411+
4412+
def _to_lease(self, obj):
4413+
return OpenStack_2_Lease(
4414+
id=obj["id"],
4415+
name=obj["name"],
4416+
start=obj["start_date"],
4417+
end=obj["end_date"],
4418+
status=obj["status"],
4419+
reservations=obj["reservations"],
4420+
driver=self.reservation_connection.driver,
4421+
)
4422+
4423+
def ex_list_hosts(self):
4424+
"""
4425+
List leases
4426+
4427+
:rtype: ``list`` of :class:`OpenStack_2_Host`
4428+
"""
4429+
return self._to_hosts(self.reservation_connection.request("/os-hosts").object)
4430+
4431+
def _to_hosts(self, obj):
4432+
host_elements = obj["hosts"]
4433+
return [self._to_host(host) for host in host_elements]
4434+
4435+
def _to_host(self, obj):
4436+
return OpenStack_2_Host(
4437+
id=obj["id"],
4438+
hypervisor_hostname=obj["hypervisor_hostname"],
4439+
vcpus=obj["vcpus"],
4440+
memory_mb=obj["memory_mb"],
4441+
local_gb=obj["local_gb"],
4442+
service_name=obj["service_name"],
4443+
)
4444+
4445+
4446+
class OpenStack_2_Host:
4447+
"""
4448+
Host info.
4449+
"""
4450+
4451+
def __init__(self, id, hypervisor_hostname, vcpus, memory_mb, local_gb, service_name):
4452+
self.id = id
4453+
self.hypervisor_hostname = hypervisor_hostname
4454+
self.vcpus = vcpus
4455+
self.memory_mb = memory_mb
4456+
self.local_gb = local_gb
4457+
self.service_name = service_name
4458+
4459+
def __repr__(self):
4460+
return "<OpenStack_2_Host: id={}, hypervisor_hostname={}>".format(
4461+
self.id,
4462+
self.hypervisor_hostname,
4463+
)
4464+
4465+
4466+
class OpenStack_2_Lease:
4467+
"""
4468+
Lease info.
4469+
"""
4470+
4471+
PENDING = "PENDING"
4472+
ACTIVE = "ACTIVE"
4473+
TERMINATED = "TERMINATED"
4474+
DELETED = "DELETED"
4475+
CREATING = "CREATING"
4476+
UPDATING = "UPDATING"
4477+
DELETING = "DELETING"
4478+
ERROR = "ERROR"
4479+
4480+
def __init__(self, id, name, start, end, status, reservations, driver):
4481+
self.id = id
4482+
self.name = name
4483+
self.start = start
4484+
self.end = end
4485+
self.status = status
4486+
self.reservations = reservations
4487+
self.driver = driver
4488+
4489+
def __repr__(self):
4490+
return "<OpenStack_2_Lease: id={}, name={}, status={}>".format(
4491+
self.id, self.name, self.status
4492+
)
4493+
43714494

43724495
class OpenStack_1_1_FloatingIpPool:
43734496
"""

libcloud/test/common/test_openstack_identity.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ def test_parsing_auth_v2(self):
833833

834834
catalog = OpenStackServiceCatalog(service_catalog=service_catalog, auth_version="2.0")
835835
entries = catalog.get_entries()
836-
self.assertEqual(len(entries), 10)
836+
self.assertEqual(len(entries), 11)
837837

838838
entry = [e for e in entries if e.service_name == "cloudServers"][0]
839839
self.assertEqual(entry.service_type, "compute")
@@ -904,6 +904,7 @@ def test_get_service_types(self):
904904
"network",
905905
"object-store",
906906
"rax:object-cdn",
907+
"reservation",
907908
"volumev2",
908909
"volumev3",
909910
],
@@ -923,6 +924,7 @@ def test_get_service_names(self):
923924
self.assertEqual(
924925
service_names,
925926
[
927+
"blazar",
926928
"cinderv2",
927929
"cinderv3",
928930
"cloudFiles",

libcloud/test/compute/fixtures/openstack/_v2_0__auth.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@
164164
"name": "cinderv3",
165165
"type": "volumev3"
166166
},
167+
{
168+
"endpoints": [
169+
{
170+
"region": "RegionOne",
171+
"tenantId": "1337",
172+
"publicURL": "https://test_endpoint.com/v1",
173+
"versionInfo": "https://test_endpoint.com/v1/",
174+
"versionList": "https://test_endpoint.com/",
175+
"versionId": "1"
176+
}
177+
],
178+
"name": "blazar",
179+
"type": "reservation"
180+
},
167181
{
168182
"endpoints": [
169183
{
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"leases": [
3+
{
4+
"id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
5+
"name": "lease_foo",
6+
"start_date": "2017-12-26T12:00:00.000000",
7+
"end_date": "2017-12-27T12:00:00.000000",
8+
"status":"PENDING",
9+
"degraded": false,
10+
"user_id": "5434f637520d4c17bbf254af034b0320",
11+
"project_id": "aa45f56901ef45ee95e3d211097c0ea3",
12+
"trust_id": "b442a580b9504ababf305bf2b4c49512",
13+
"created_at": "2017-12-27 10:00:00",
14+
"updated_at": null,
15+
"reservations": [
16+
{
17+
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
18+
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
19+
"status": "pending",
20+
"missing_resources": false,
21+
"resources_changed": false,
22+
"resource_id": "5e6c0e6e-f1e6-490b-baaf-50deacbbe371",
23+
"resource_type": "physical:host",
24+
"min": 4,
25+
"max": 6,
26+
"hypervisor_properties": "[\">=\", \"$vcpus\", \"4\"]",
27+
"resource_properties": "",
28+
"before_end": "default",
29+
"created_at": "2017-12-27 10:00:00",
30+
"updated_at": null
31+
},
32+
{
33+
"id": "ddc45423-f863-4e4e-8e7a-51d27cfec962",
34+
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
35+
"status": "pending",
36+
"missing_resources": false,
37+
"resources_changed": false,
38+
"resource_id": "0b901727-cca2-43ed-bcc8-c21b0982dcb1",
39+
"resource_type": "virtual:instance",
40+
"amount": 4,
41+
"vcpus": 2,
42+
"memory_mb": 4096,
43+
"disk_gb": 100,
44+
"affinity": false,
45+
"resource_properties": "",
46+
"flavor_id": "ddc45423-f863-4e4e-8e7a-51d27cfec962",
47+
"server_group_id": "33cdfc42-5a04-4fcc-b190-1abebaa056bb",
48+
"aggregate_id": 11,
49+
"created_at": "2017-12-27 10:00:00",
50+
"updated_at": null
51+
}
52+
],
53+
"events": [
54+
{
55+
"id": "188a8584-f832-4df9-9a4a-51e6364420ff",
56+
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
57+
"status": "UNDONE",
58+
"event_type": "start_lease",
59+
"time": "2017-12-26T12:00:00.000000",
60+
"created_at": "2017-12-27 10:00:00",
61+
"updated_at": null
62+
},
63+
{
64+
"id": "277d6436-dfcb-4eae-ae5e-ac7fa9c2fd56",
65+
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
66+
"status": "UNDONE",
67+
"event_type": "end_lease",
68+
"time": "2017-12-27T12:00:00.000000",
69+
"created_at": "2017-12-27 10:00:00",
70+
"updated_at": null
71+
},
72+
{
73+
"id": "f583af71-ca21-4b66-87de-52211d118029",
74+
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
75+
"status": "UNDONE",
76+
"time": "2017-12-27T11:00:00.000000",
77+
"event_type": "before_end_lease",
78+
"created_at": "2017-12-27 10:00:00",
79+
"updated_at": null
80+
}
81+
]
82+
}
83+
]
84+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"hosts": [
3+
{
4+
"id": "1",
5+
"hypervisor_hostname": "compute-1",
6+
"hypervisor_type": "QEMU",
7+
"hypervisor_version": 2010001,
8+
"vcpus": 4,
9+
"cpu_info": "{'arch': 'x86_64', 'model': 'cpu64-rhel6', 'vendor': 'Intel'}",
10+
"memory_mb": 8192,
11+
"local_gb": 100,
12+
"service_name": "compute-1",
13+
"reservable": true,
14+
"status": null,
15+
"trust_id": "5f67f11215cf4c52906453a181bfcfea",
16+
"created_at": "2017-12-27 10:00:00",
17+
"updated_at": null,
18+
"extra_capability_sample": "foo"
19+
}
20+
]
21+
}

libcloud/test/compute/test_openstack.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,11 @@ def setUp(self):
20052005
# normally authentication happens lazily, but we force it here
20062006
self.driver.volumev3_connection._populate_hosts_and_request_paths()
20072007

2008+
self.driver_klass.reservation_connectionCls.conn_class = OpenStack_2_0_MockHttp
2009+
self.driver_klass.reservation_connectionCls.auth_url = "https://auth.api.example.com"
2010+
# normally authentication happens lazily, but we force it here
2011+
self.driver.reservation_connection._populate_hosts_and_request_paths()
2012+
20082013
def test__paginated_request_single_page(self):
20092014
snapshots = self.driver._paginated_request(
20102015
"/snapshots/detail", "snapshots", self.driver._get_volume_connection()
@@ -2547,6 +2552,22 @@ def test_ex_delete_floating_ip(self):
25472552
ip = OpenStack_1_1_FloatingIpAddress("foo-bar-id", "42.42.42.42", None)
25482553
self.assertTrue(self.driver.ex_delete_floating_ip(ip))
25492554

2555+
def test_ex_list_leases(self):
2556+
leases = self.driver.ex_list_leases()
2557+
self.assertEqual(len(leases), 1)
2558+
self.assertEqual(leases[0].id, "6ee55c78-ac52-41a6-99af-2d2d73bcc466")
2559+
self.assertEqual(leases[0].name, "lease_foo")
2560+
self.assertEqual(leases[0].start, "2017-12-26T12:00:00.000000")
2561+
self.assertEqual(leases[0].end, "2017-12-27T12:00:00.000000")
2562+
self.assertEqual(leases[0].status, "PENDING")
2563+
2564+
def test_ex_list_hosts(self):
2565+
hosts = self.driver.ex_list_hosts()
2566+
self.assertEqual(len(hosts), 1)
2567+
self.assertEqual(hosts[0].id, "1")
2568+
self.assertEqual(hosts[0].hypervisor_hostname, "compute-1")
2569+
self.assertEqual(hosts[0].vcpus, 4)
2570+
25502571
def test_ex_attach_floating_ip_to_node(self):
25512572
image = NodeImage(id=11, name="Ubuntu 8.10 (intrepid)", driver=self.driver)
25522573
size = NodeSize(1, "256 slice", None, None, None, None, driver=self.driver)
@@ -4004,6 +4025,28 @@ def _v2_1337_servers_4242_os_interface(self, method, url, body, headers):
40044025
httplib.responses[httplib.OK],
40054026
)
40064027

4028+
def _v1_leases(self, method, url, body, headers):
4029+
if method == "GET":
4030+
body = self.fixtures.load("_leases.json")
4031+
4032+
return (
4033+
httplib.OK,
4034+
body,
4035+
self.json_content_headers,
4036+
httplib.responses[httplib.OK],
4037+
)
4038+
4039+
def _v1_os_hosts(self, method, url, body, headers):
4040+
if method == "GET":
4041+
body = self.fixtures.load("_os_hosts.json")
4042+
4043+
return (
4044+
httplib.OK,
4045+
body,
4046+
self.json_content_headers,
4047+
httplib.responses[httplib.OK],
4048+
)
4049+
40074050

40084051
# This exists because the nova compute url in devstack has v2 in there but the v1.1 fixtures
40094052
# work fine.

0 commit comments

Comments
 (0)