Skip to content

Commit 864c68e

Browse files
authored
Merge pull request #13 from cloudify-incubator/storage-support
Storage support
2 parents e0d75f1 + 06fe833 commit 864c68e

21 files changed

Lines changed: 1041 additions & 266 deletions

CHANGELOG.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ releases:
2626
* move use_external_resource to top of instance properties
2727
* add `update` action for sync vm size to values from runtime properties.
2828
* rename `memory_size` to `memory_maxsize`
29+
30+
v0.7.0:
31+
* Support storage pool creation.
32+
* Rename `params.resource_id` to `params.name`.
33+
* Support creation snapshot on external resources.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Description for VM
4646
* `resource_id`: (optional) Used to identify the object when
4747
`use_external_resource` is true.
4848
* `params`: params used for create object, useful for embeded template.
49+
* `name`: Domain name
4950
* `vcpu`: CPU count
5051
* `memory_size`: VM memory size in KiB
5152
* `memory_maxsize`: (optional) recomended VM memory size in KiB for
@@ -62,7 +63,7 @@ Description for VM
6263
**Inputs for actions:**
6364
* `configure`:
6465
* `params`: list of params for template, can be empty
65-
* `domain_file`: Template for domain. Defaults is
66+
* `template_resource`: Template for domain. Defaults is
6667
[domain.xml](cloudify_libvirt/templates/domain.xml)
6768

6869
**Runtime properties:**
@@ -80,14 +81,15 @@ Description for Network
8081
* `resource_id`: (optional) Used to identify the object when
8182
`use_external_resource` is true.
8283
* `params`: params used for create object.
84+
* `name`: Network name
8385
* `dev`: Device name
8486
* `forwards`: settings for network `forwards`.
8587
* `ips`: settings for network `ips`.
8688

8789
**Inputs for actions:**
8890
* `create`:
8991
* `params`: list of params for template, can be empty
90-
* `network_file`: Template for network. Defaults is
92+
* `template_resource`: Template for network. Defaults is
9193
[network.xml](cloudify_libvirt/templates/network.xml)
9294

9395
**Runtime properties:**

cloudify_libvirt/common.py

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
import os
16+
import uuid
17+
from jinja2 import Template
18+
from pkg_resources import resource_filename
19+
1620
from cloudify import ctx
1721
from cloudify import exceptions as cfy_exc
1822

@@ -32,6 +36,12 @@ def get_libvirt_params(**kwargs):
3236
template_params.update(kwargs.get('params', {}))
3337
ctx.instance.runtime_properties['params'] = template_params
3438

39+
# set default names and instance_uuid
40+
if not template_params.get("name"):
41+
template_params["name"] = ctx.instance.id
42+
if not template_params.get("instance_uuid"):
43+
template_params["instance_uuid"] = str(uuid.uuid4())
44+
3545
# update 'resource_id', 'use_external_resource' from kwargs
3646
for field in ['resource_id', 'use_external_resource']:
3747
if field in kwargs:
@@ -40,12 +50,38 @@ def get_libvirt_params(**kwargs):
4050
return libvirt_auth, template_params
4151

4252

53+
def gen_xml_template(kwargs, template_params, default_template):
54+
# templates
55+
template_resource = kwargs.get('template_resource')
56+
template_content = kwargs.get('template_content')
57+
58+
if template_resource:
59+
template_content = ctx.get_resource(template_resource)
60+
61+
if not (template_resource or template_content):
62+
resource_dir = resource_filename(__name__, 'templates')
63+
template_resource = '{}/{}.xml'.format(resource_dir, default_template)
64+
ctx.logger.info("Will be used internal: %s" % template_resource)
65+
66+
if not template_content:
67+
with open(template_resource) as object_desc:
68+
template_content = object_desc.read()
69+
70+
template_engine = Template(template_content)
71+
params = {"ctx": ctx}
72+
if template_params:
73+
params.update(template_params)
74+
xmlconfig = template_engine.render(params)
75+
ctx.logger.debug(repr(xmlconfig))
76+
return xmlconfig
77+
78+
4379
def get_backupname(kwargs):
4480
if not kwargs.get("snapshot_name"):
4581
raise cfy_exc.NonRecoverableError(
4682
'Backup name must be provided.'
4783
)
48-
return kwargs["snapshot_name"]
84+
return "{}-{}".format(ctx.instance.id, kwargs["snapshot_name"])
4985

5086

5187
def get_backupdir(kwargs):
@@ -99,3 +135,71 @@ def delete_binary_place(backup_dir, object_name):
99135
full_path = get_binary_place(backup_dir, object_name)
100136
if os.path.isfile(full_path):
101137
os.remove(full_path)
138+
139+
140+
def xml_snapshot_create(kwargs, resource_id, current_xmldump):
141+
snapshot_name = get_backupname(kwargs)
142+
if kwargs.get("snapshot_incremental"):
143+
backups = ctx.instance.runtime_properties.get("backups", {})
144+
if snapshot_name in backups:
145+
raise cfy_exc.NonRecoverableError(
146+
"Snapshot {snapshot_name} already exists."
147+
.format(snapshot_name=snapshot_name,))
148+
backups[snapshot_name] = current_xmldump
149+
ctx.instance.runtime_properties["backups"] = backups
150+
ctx.logger.info("Snapshot {snapshot_name} is created."
151+
.format(snapshot_name=snapshot_name,))
152+
else:
153+
if read_node_state(get_backupdir(kwargs), resource_id):
154+
raise cfy_exc.NonRecoverableError(
155+
"Backup {snapshot_name} already exists."
156+
.format(snapshot_name=snapshot_name,))
157+
save_node_state(get_backupdir(kwargs), resource_id, current_xmldump)
158+
ctx.logger.info("Backup {snapshot_name} is created."
159+
.format(snapshot_name=snapshot_name,))
160+
ctx.logger.debug("Current config {}".format(repr(current_xmldump)))
161+
162+
163+
def xml_snapshot_apply(kwargs, resource_id, current_xmldump):
164+
snapshot_name = get_backupname(kwargs)
165+
if kwargs.get("snapshot_incremental"):
166+
backups = ctx.instance.runtime_properties.get("backups", {})
167+
if snapshot_name not in backups:
168+
raise cfy_exc.NonRecoverableError(
169+
"No snapshots found with name: {snapshot_name}."
170+
.format(snapshot_name=snapshot_name,))
171+
xml_backup = backups[snapshot_name]
172+
else:
173+
xml_backup = read_node_state(get_backupdir(kwargs), resource_id)
174+
if not xml_backup:
175+
raise cfy_exc.NonRecoverableError(
176+
"No backups found with name: {snapshot_name}."
177+
.format(snapshot_name=snapshot_name,))
178+
179+
if xml_backup.strip() != current_xmldump.strip():
180+
ctx.logger.info("We have different configs,\n{}\nvs\n{}\n"
181+
.format(
182+
repr(xml_backup.strip()),
183+
repr(current_xmldump.strip())))
184+
else:
185+
ctx.logger.info("Already used such configuration: {}"
186+
.format(snapshot_name))
187+
188+
189+
def xml_snapshot_delete(kwargs, resource_id):
190+
snapshot_name = get_backupname(kwargs)
191+
if kwargs.get("snapshot_incremental"):
192+
backups = ctx.instance.runtime_properties.get("backups", {})
193+
if snapshot_name not in backups:
194+
raise cfy_exc.NonRecoverableError(
195+
"No snapshots found with name: {snapshot_name}."
196+
.format(snapshot_name=snapshot_name,))
197+
del backups[snapshot_name]
198+
ctx.instance.runtime_properties["backups"] = backups
199+
else:
200+
if not read_node_state(get_backupdir(kwargs), resource_id):
201+
raise cfy_exc.NonRecoverableError(
202+
"No backups found with name: {snapshot_name}."
203+
.format(snapshot_name=snapshot_name,))
204+
delete_node_state(get_backupdir(kwargs), resource_id)
205+
ctx.logger.info("Backup deleted: {}".format(snapshot_name))

cloudify_libvirt/domain_tasks.py

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@
1515

1616
import libvirt
1717
import time
18-
import uuid
1918

20-
from jinja2 import Template
2119
from cloudify import ctx
2220
from cloudify.decorators import operation
2321
from cloudify import exceptions as cfy_exc
24-
from pkg_resources import resource_filename
2522
import cloudify_libvirt.common as common
2623

2724

@@ -35,22 +32,14 @@ def create(**kwargs):
3532

3633
def _update_template_params(template_params):
3734
# set all params to default values
38-
if not template_params:
39-
template_params = {}
40-
41-
if not template_params.get("resource_id"):
42-
template_params["resource_id"] = ctx.instance.id
4335
if (not template_params.get("memory_maxsize") and
4436
template_params.get('memory_size')):
4537
# if have no maximum memory size, set current as minimum
4638
# and twised memory as maximum
4739
memory_size = int(template_params['memory_size'])
4840
template_params['memory_maxsize'] = memory_size * 2
49-
if not template_params.get("instance_uuid"):
50-
template_params["instance_uuid"] = str(uuid.uuid4())
5141
if not template_params.get("domain_type"):
5242
template_params["domain_type"] = "qemu"
53-
return template_params
5443

5544

5645
@operation
@@ -64,8 +53,7 @@ def configure(**kwargs):
6453
'Failed to open connection to the hypervisor'
6554
)
6655

67-
template_params = _update_template_params(template_params)
68-
56+
_update_template_params(template_params)
6957
try:
7058
if ctx.instance.runtime_properties.get("use_external_resource"):
7159
# lookup the default domain by name
@@ -83,29 +71,7 @@ def configure(**kwargs):
8371
ctx.instance.runtime_properties['use_external_resource'] = True
8472
return
8573

86-
# templates
87-
domain_file = kwargs.get('domain_file')
88-
domain_template = kwargs.get('domain_template')
89-
90-
if domain_file:
91-
domain_template = ctx.get_resource(domain_file)
92-
93-
if not (domain_file or domain_template):
94-
resource_dir = resource_filename(__name__, 'templates')
95-
domain_file = '{}/domain.xml'.format(resource_dir)
96-
ctx.logger.info("Will be used internal: %s" % domain_file)
97-
98-
if not domain_template:
99-
with open(domain_file) as domain_desc:
100-
domain_template = domain_desc.read()
101-
102-
template_engine = Template(domain_template)
103-
params = {"ctx": ctx}
104-
params.update(template_params)
105-
xmlconfig = template_engine.render(params)
106-
107-
ctx.logger.debug(repr(xmlconfig))
108-
74+
xmlconfig = common.gen_xml_template(kwargs, template_params, 'domain')
10975
dom = conn.defineXML(xmlconfig)
11076
if dom is None:
11177
raise cfy_exc.NonRecoverableError(
@@ -598,35 +564,15 @@ def snapshot_create(**kwargs):
598564
)
599565

600566
if kwargs.get("snapshot_incremental"):
601-
backup_file = kwargs.get('backup_file')
602-
backup_template = kwargs.get('backup_template')
603567
snapshot_type = kwargs.get('snapshot_type')
604568

605-
if backup_file:
606-
backup_template = ctx.get_resource(backup_file)
607-
608-
if not backup_file and not backup_template:
609-
resource_dir = resource_filename(__name__, 'templates')
610-
backup_file = '{}/snapshot.xml'.format(resource_dir)
611-
ctx.logger.info("Will be used internal: %s" % backup_file)
612-
613-
if not backup_template:
614-
with open(backup_file) as backup_desc:
615-
backup_template = backup_desc.read()
616-
617-
template_engine = Template(backup_template)
618-
if not template_params:
619-
template_params = {}
620-
621569
params = {
622-
"ctx": ctx,
623570
'snapshot_name': snapshot_name,
624571
'snapshot_description': snapshot_type
625572
}
626-
params.update(template_params)
627-
xmlconfig = template_engine.render(params)
628-
629-
ctx.logger.debug(repr(xmlconfig))
573+
if template_params:
574+
params.update(template_params)
575+
xmlconfig = common.gen_xml_template(kwargs, params, 'snapshot')
630576

631577
try:
632578
# will raise exception if unexist

0 commit comments

Comments
 (0)