Skip to content

Commit c504c2e

Browse files
authored
Merge pull request #26 from cloudify-incubator/fortigate
Add example for directly download volume content from http
2 parents 7c8bed3 + c61016d commit c504c2e

File tree

17 files changed

+1464
-93
lines changed

17 files changed

+1464
-93
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
command: pip install --upgrade pip==9.0.1
6060
- run:
6161
name: Install virtualenv
62-
command: pip install virtualenv
62+
command: pip install virtualenv==16.7.9
6363
- run:
6464
name: Init virtualenv
6565
command: virtualenv env

CHANGELOG.txt

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
releases:
22

3-
v0.1: Implement minimal functionality for create network and virtual machine
4-
based on embeded template.
3+
v0.1:
4+
* Implement minimal functionality for create network and virtual machine
5+
based on embeded template.
56

6-
v0.2: Add arm support and autogenerate mac addresses in examples
7+
v0.2:
8+
* Add arm support and autogenerate mac addresses in examples
79

8-
v0.3: Fix network validation and use virtio devices in embeded templates
10+
v0.3:
11+
* Fix network validation and use virtio devices in embeded templates
912

1013
v0.4:
1114
* Add cluster example with external ip support
@@ -15,25 +18,28 @@ releases:
1518
v0.4.1: Add support for disk/network backup/snapshots
1619

1720
v0.5.0:
18-
* Support for reuse external network
19-
* Support for kvm virtualization in embeded examples
21+
* Support for reuse external network
22+
* Support for kvm virtualization in embeded examples
2023

2124
v0.6.0:
22-
* Support for dump full vm snapshot to fs on backup
23-
* Update start action for fill in `network` in vm runtime properties
24-
* Cluster Example: Automatically add libvirt host to trusted
25-
* Support for reuse external vm
26-
* move use_external_resource to top of instance properties
27-
* add `update` action for sync vm size to values from runtime properties.
28-
* rename `memory_size` to `memory_maxsize`
25+
* Support for dump full vm snapshot to fs on backup
26+
* Update start action for fill in `network` in vm runtime properties
27+
* Cluster Example: Automatically add libvirt host to trusted
28+
* Support for reuse external vm
29+
* move use_external_resource to top of instance properties
30+
* add `update` action for sync vm size to values from runtime properties.
31+
* rename `memory_size` to `memory_maxsize`
2932

3033
v0.7.0:
31-
* Support storage pool creation.
32-
* Rename `params.resource_id` to `params.name`.
33-
* Support creation snapshot on external resources.
34+
* Support storage pool creation.
35+
* Rename `params.resource_id` to `params.name`.
36+
* Support creation snapshot on external resources.
3437

3538
v0.8.0:
36-
* Support storage volume creation.
39+
* Support storage volume creation.
3740

3841
v0.8.1:
39-
* Fix volume wipe code.
42+
* Fix volume wipe code.
43+
44+
v0.9.0:
45+
* Support download image contwent from external resource

cloudify_libvirt/common.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
# limitations under the License.
1414
import os
1515
import uuid
16-
from jinja2 import Template
1716
from pkg_resources import resource_filename
1817

1918
from cloudify import ctx
2019
from cloudify import exceptions as cfy_exc
2120

21+
from cloudify_common_sdk import filters
22+
2223

2324
def get_libvirt_params(**kwargs):
2425
libvirt_auth = kwargs.get('libvirt_auth')
@@ -66,11 +67,10 @@ def gen_xml_template(kwargs, template_params, default_template):
6667
with open(template_resource) as object_desc:
6768
template_content = object_desc.read()
6869

69-
template_engine = Template(template_content)
7070
params = {"ctx": ctx}
7171
if template_params:
7272
params.update(template_params)
73-
xmlconfig = template_engine.render(params)
73+
xmlconfig = filters.render_template(template_content, params)
7474
ctx.logger.debug(repr(xmlconfig))
7575
return xmlconfig
7676

cloudify_libvirt/iso9660_tasks.py

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,14 @@
1313
# limitations under the License.
1414

1515
import libvirt
16-
import pycdlib
1716
import os
18-
import re
19-
from io import BytesIO
2017

2118
from cloudify import ctx
2219
from cloudify.decorators import operation
2320
from cloudify import exceptions as cfy_exc
24-
import cloudify_libvirt.common as common
25-
26-
27-
def _joliet_name(name):
28-
if name[0] == "/":
29-
name = name[1:]
30-
return "/{}".format(name[:64])
31-
32-
33-
def _name_cleanup(name):
34-
return re.sub('[^A-Z0-9_]{1}', r'_', name.upper())
21+
import cloudify_common_sdk.iso9660 as iso9660
3522

36-
37-
def _iso_name(name):
38-
if name[0] == "/":
39-
name = name[1:]
40-
41-
name_splited = name.split('.')
42-
if len(name_splited[-1]) <= 3 and len(name_splited) > 1:
43-
return "/{}.{};1".format(
44-
_name_cleanup("_".join(name_splited[:-1])[:8]),
45-
_name_cleanup(name_splited[-1]))
46-
else:
47-
return "/{}.;1".format(_name_cleanup(name[:8]))
23+
import cloudify_libvirt.common as common
4824

4925

5026
@operation
@@ -68,22 +44,16 @@ def create(**kwargs):
6844
'Failed to find the volume: {}'.format(repr(e))
6945
)
7046

71-
iso = pycdlib.PyCdlib()
72-
iso.new(vol_ident='cidata', joliet=3, rock_ridge='1.09')
47+
outiso = iso9660.create_iso(
48+
vol_ident=template_params.get('vol_ident', 'cidata'),
49+
sys_ident=template_params.get('sys_ident', ""),
50+
get_resource=ctx.get_resource,
51+
files=template_params.get('files', {}),
52+
files_raw=template_params.get('files_raw', {}))
7353

74-
fstree = template_params.get('files', {})
75-
for name in fstree:
76-
file_bufer = BytesIO()
77-
file_bufer.write(fstree[name].encode())
78-
iso.add_fp(file_bufer, len(fstree[name]),
79-
_iso_name(name), rr_name=name,
80-
joliet_path=_joliet_name(name))
81-
82-
outiso = BytesIO()
83-
iso.write_fp(outiso)
8454
outiso.seek(0, os.SEEK_END)
8555
iso_size = outiso.tell()
86-
iso.close()
56+
outiso.seek(0, os.SEEK_SET)
8757

8858
ctx.logger.info("ISO size: {}".format(repr(iso_size)))
8959

cloudify_libvirt/pool_tasks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ def delete(**kwargs):
252252
'Failed to find the pool: {}'.format(repr(e))
253253
)
254254

255+
if pool.delete() < 0:
256+
raise cfy_exc.RecoverableError(
257+
'Can not delete pool.'
258+
)
259+
255260
if pool.undefine() < 0:
256261
raise cfy_exc.NonRecoverableError(
257262
'Can not undefine pool.'

cloudify_libvirt/tests/test_domain.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,19 @@ def test_configure(self):
134134
self.assertEqual(
135135
_ctx.instance.runtime_properties['resource_id'], "domain_name"
136136
)
137+
# check rerun after create
138+
with mock.patch(
139+
"cloudify_libvirt.domain_tasks.libvirt.open",
140+
mock.Mock(return_value=connect)
141+
):
142+
connect.lookupByName = mock.Mock(
143+
side_effect=domain_tasks.libvirt.libvirtError("e"))
144+
with self.assertRaisesRegexp(
145+
NonRecoverableError,
146+
'Failed to find the domain:'
147+
):
148+
domain_tasks.configure(ctx=_ctx,
149+
template_resource="template_resource")
137150
# with params from inputs
138151
_ctx.instance.runtime_properties['resource_id'] = None
139152
_ctx.instance.runtime_properties['params'] = {}

cloudify_libvirt/tests/test_iso9660_tasks.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,6 @@
2020

2121
class TestIso9660Task(LibVirtCommonTest):
2222

23-
def test_joliet_name(self):
24-
self.assertEqual("/abc", iso9660_tasks._joliet_name("abc"))
25-
self.assertEqual("/" + "*" * 64, iso9660_tasks._joliet_name("*" * 128))
26-
self.assertEqual("/" + "*" * 64,
27-
iso9660_tasks._joliet_name("/" + "*" * 128))
28-
29-
def test_iso_name(self):
30-
self.assertEqual("/ABC.;1", iso9660_tasks._iso_name("abc"))
31-
self.assertEqual("/12345678.;1",
32-
iso9660_tasks._iso_name("1234567890.abcdef"))
33-
self.assertEqual("/" + "_" * 8 + ".;1",
34-
iso9660_tasks._iso_name("*" * 128))
35-
self.assertEqual("/" + "_" * 8 + ".;1",
36-
iso9660_tasks._iso_name("/" + "*" * 128))
37-
self.assertEqual("/12345678.123;1",
38-
iso9660_tasks._iso_name("12345678.123"))
39-
4023
def test_create(self):
4124
# check correct handle exception with empty connection
4225
self._check_correct_connect(

cloudify_libvirt/tests/test_network.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,20 @@ def test_create(self):
553553
_ctx.instance.runtime_properties['resource_id'], "network_name"
554554
)
555555

556+
# rerun on created
557+
connect.networkLookupByName = mock.Mock(
558+
side_effect=network_tasks.libvirt.libvirtError("e"))
559+
with mock.patch(
560+
"cloudify_libvirt.network_tasks.libvirt.open",
561+
mock.Mock(return_value=connect)
562+
):
563+
with self.assertRaisesRegexp(
564+
NonRecoverableError,
565+
'Failed to find the network.'
566+
):
567+
network_tasks.create(ctx=_ctx,
568+
template_resource="template_resource")
569+
556570

557571
if __name__ == '__main__':
558572
unittest.main()

cloudify_libvirt/tests/test_pool.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,22 @@ def test_delete(self):
579579
"Can not undefine pool."
580580
):
581581
pool_tasks.delete(ctx=_ctx)
582+
583+
# remove with delete issues
584+
pool.delete = mock.Mock(return_value=-1)
585+
pool.undefine = mock.Mock(return_value=0)
586+
with mock.patch(
587+
"cloudify_libvirt.pool_tasks.libvirt.open",
588+
mock.Mock(return_value=connect)
589+
):
590+
with self.assertRaisesRegexp(
591+
RecoverableError,
592+
"Can not delete pool."
593+
):
594+
pool_tasks.delete(ctx=_ctx)
595+
582596
# remove witout issues
597+
pool.delete = mock.Mock(return_value=0)
583598
pool.undefine = mock.Mock(return_value=0)
584599
with mock.patch(
585600
"cloudify_libvirt.pool_tasks.libvirt.open",

cloudify_libvirt/tests/test_volume.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,58 @@ def test_create(self):
351351
_ctx.instance.runtime_properties['resource_id'], "volume_name"
352352
)
353353

354+
# failed check size of download
355+
_ctx.instance.runtime_properties['resource_id'] = None
356+
_ctx.instance.runtime_properties['params'] = {}
357+
_ctx.node.properties['params'] = {}
358+
with mock.patch(
359+
"cloudify_libvirt.volume_tasks.libvirt.open",
360+
mock.Mock(return_value=connect)
361+
):
362+
# empty
363+
head_response = mock.Mock()
364+
head_response.headers = {'Content-Length': 0}
365+
with mock.patch(
366+
"cloudify_libvirt.volume_tasks.requests.head",
367+
mock.Mock(return_value=head_response)
368+
):
369+
with self.assertRaisesRegexp(
370+
NonRecoverableError,
371+
"Failed to download volume."
372+
):
373+
volume_tasks.create(
374+
ctx=_ctx,
375+
template_resource="template_resource",
376+
params={
377+
'pool': 'empty',
378+
'url': "https://fake.org/centos.iso"})
379+
380+
# sucessful check size of download
381+
_ctx.instance.runtime_properties['resource_id'] = None
382+
_ctx.instance.runtime_properties['params'] = {}
383+
_ctx.node.properties['params'] = {}
384+
with mock.patch(
385+
"cloudify_libvirt.volume_tasks.libvirt.open",
386+
mock.Mock(return_value=connect)
387+
):
388+
head_response = mock.Mock()
389+
head_response.headers = {'Content-Length': 512,
390+
'Accept-Ranges': 'bytes'}
391+
with mock.patch(
392+
"cloudify_libvirt.volume_tasks.requests.head",
393+
mock.Mock(return_value=head_response)
394+
):
395+
volume_tasks.create(
396+
ctx=_ctx,
397+
template_resource="template_resource",
398+
params={
399+
'pool': 'empty',
400+
'url': "https://fake.org/centos.iso"})
401+
354402
# failed on create
403+
_ctx.instance.runtime_properties['resource_id'] = None
404+
_ctx.instance.runtime_properties['params'] = {}
405+
_ctx.node.properties['params'] = {}
355406
pool.createXML = mock.Mock(return_value=None)
356407
with mock.patch(
357408
"cloudify_libvirt.volume_tasks.libvirt.open",
@@ -444,6 +495,60 @@ def test_start_wipe(self):
444495
'allocation': 1
445496
})
446497

498+
def test_start_download(self):
499+
# download
500+
_ctx = self._create_ctx()
501+
_ctx.instance.runtime_properties['resource_id'] = 'volume'
502+
_ctx.instance.runtime_properties['params'] = {'pool': 'pool_name'}
503+
504+
volume = mock.Mock()
505+
volume.name = mock.Mock(return_value="volume")
506+
volume.upload = mock.Mock()
507+
pool = mock.Mock()
508+
pool.name = mock.Mock(return_value="pool")
509+
pool.storageVolLookupByName = mock.Mock(return_value=volume)
510+
511+
connect = self._create_fake_connection()
512+
513+
connect.storagePoolLookupByName = mock.Mock(return_value=pool)
514+
with mock.patch(
515+
"cloudify_libvirt.volume_tasks.libvirt.open",
516+
mock.Mock(return_value=connect)
517+
):
518+
# empty
519+
head_response = mock.Mock()
520+
head_response.headers = {'Content-Length': 0}
521+
with mock.patch(
522+
"cloudify_libvirt.volume_tasks.requests.head",
523+
mock.Mock(return_value=head_response)
524+
):
525+
with self.assertRaisesRegexp(
526+
NonRecoverableError,
527+
"Failed to download volume."
528+
):
529+
volume_tasks.start(
530+
ctx=_ctx,
531+
params={
532+
'url': "https://fake.org/centos.iso"})
533+
534+
# 512 for download
535+
head_response = mock.Mock()
536+
head_response.headers = {'Content-Length': 512,
537+
'Accept-Ranges': 'bytes'}
538+
head_response.iter_content = mock.Mock(return_value=["\0" * 256])
539+
with mock.patch(
540+
"cloudify_libvirt.volume_tasks.requests.head",
541+
mock.Mock(return_value=head_response)
542+
):
543+
with mock.patch(
544+
"cloudify_libvirt.volume_tasks.requests.get",
545+
mock.Mock(return_value=head_response)
546+
):
547+
volume_tasks.start(
548+
ctx=_ctx,
549+
params={
550+
'url': "https://fake.org/centos.iso"})
551+
447552
def test_stop(self):
448553
# check correct handle exception with empty connection
449554
self._test_check_correct_connect_action(

0 commit comments

Comments
 (0)