Skip to content

Commit df6bf27

Browse files
Prashanth684cgwalters
authored andcommittedJun 28, 2021
Add PowerVS as a new platform
This commit does a few things: - add support for a new `buildextend-powervs` command which supports building powervs ovas and uploading them to ibmcloud - make `buildextend-ibmcloud` symlink to cmd-ore-wrapper now that image uploads are supported - move ibmcloud and powervs specifics into one file as powervs is an extension of ibmcloud - add the ovf template file for powervs PowerVS image specifics - the powervs ova contains: - raw disk image (with the default size 16G) - a meta file which contains some details for display purposes in the ibmcloud UI - the powervs ovf template The meta file contains information such as the os type, architecture and image name. the powervs ovf template hardcodes the size of the disk image to 128G (required for PowerVS as they copy to SANs) so the virtual size of the disk is unchanged
1 parent f18c66f commit df6bf27

7 files changed

+242
-8
lines changed
 

‎src/cmd-buildextend-ibmcloud

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
cmd-artifact-disk
1+
cmd-ore-wrapper

‎src/cmd-buildextend-powervs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cmd-ore-wrapper

‎src/cmd-ore-wrapper

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ from cosalib.cli import (
1515
BuildCli
1616
)
1717
from cosalib.qemuvariants import get_qemu_variant
18+
from cosalib.ibmcloud import get_ibmcloud_variant
1819

1920
if __name__ == '__main__':
2021
log.basicConfig(
@@ -96,7 +97,10 @@ Each target has its own sub options. To access them us:
9697
sys.exit()
9798

9899
# Now _extend the parser with the cloud targets_
99-
build = get_qemu_variant(target, args)
100+
if target in ['ibmcloud', 'powervs']:
101+
build = get_ibmcloud_variant(target, args)
102+
else:
103+
build = get_qemu_variant(target, args)
100104
log.info(f"operating on {build.image_name}")
101105
if args.build_artifact:
102106
if args.force:

‎src/cosalib/cli.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
digitalocean,
1313
gcp,
1414
vultr,
15-
exoscale
15+
exoscale,
16+
ibmcloud
1617
)
1718

1819
CLOUD_CLI_TARGET = {
@@ -37,6 +38,12 @@
3738
"exoscale": (exoscale.exoscale_cli,
3839
exoscale.exoscale_run_ore,
3940
exoscale.exoscale_run_ore_replicate),
41+
"ibmcloud": (ibmcloud.ibmcloud_cli,
42+
ibmcloud.ibmcloud_run_ore,
43+
ibmcloud.ibmcloud_run_ore_replicate),
44+
"powervs": (ibmcloud.ibmcloud_cli,
45+
ibmcloud.ibmcloud_run_ore,
46+
ibmcloud.ibmcloud_run_ore_replicate),
4047
}
4148

4249

‎src/cosalib/ibmcloud.py

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/usr/bin/env python3
2+
# NOTE: PYTHONUNBUFFERED is set in cmdlib.sh for unbuffered output
3+
#
4+
# An operation that mutates a build by generating an ova
5+
import logging as log
6+
import urllib
7+
import os.path
8+
import sys
9+
from cosalib.cmdlib import (
10+
run_verbose,
11+
get_basearch
12+
)
13+
from tenacity import (
14+
retry,
15+
stop_after_attempt
16+
)
17+
18+
cosa_dir = os.path.dirname(os.path.abspath(__file__))
19+
sys.path.insert(0, f"{cosa_dir}/cosalib")
20+
sys.path.insert(0, cosa_dir)
21+
22+
from cosalib.qemuvariants import QemuVariantImage
23+
24+
25+
OVA_TEMPLATE_FILE = '/usr/lib/coreos-assembler/powervs-template.xml'
26+
27+
template_meta = """os-type = {os}
28+
architecture = {basearch}
29+
vol1-file = {image}
30+
vol1-type = boot"""
31+
32+
# Variant are OVA types that are derived from qemu images.
33+
# To define new variants that use the QCOW2/raw disk image, simply,
34+
# add its definition below:
35+
VARIANTS = {
36+
"ibmcloud": {
37+
"image_format": "qcow2",
38+
"platform": "ibmcloud",
39+
"virtual_size": "100G",
40+
},
41+
"powervs": {
42+
"image_format": "raw",
43+
"image_suffix": "ova",
44+
"platform": "powervs",
45+
"tar_members": [
46+
"disk.raw"
47+
]
48+
},
49+
}
50+
51+
52+
class IBMCloudImage(QemuVariantImage):
53+
"""
54+
PowerVSOVA's are based on the QemuVariant Image. This Class tries to do
55+
the absolute bare minium, and is effectively a wrapper around the
56+
QemuVariantImage Class. The only added functionality is the generation
57+
of the OVF paramters.
58+
"""
59+
60+
def __init__(self, **kwargs):
61+
variant = kwargs.pop("variant", "ibmcloud")
62+
kwargs.update(VARIANTS.get(variant, {}))
63+
QemuVariantImage.__init__(self, **kwargs)
64+
# Set the QemuVariant mutate_callback so that OVA is called.
65+
if variant == "powervs":
66+
self.mutate_callback = self.write_ova
67+
# Ensure that coreos.ovf is included in the tar
68+
self.ovf_path = os.path.join(self._tmpdir, "coreos.ovf")
69+
# Ensure that coreos.meta is included in the tar
70+
self.meta_path = os.path.join(self._tmpdir, "coreos.meta")
71+
72+
def generate_ovf_parameters(self, raw):
73+
"""
74+
Returns a dictionary with the parameters needed to create an OVF and meta file
75+
based on the qemu, raw, and info from the build metadata
76+
"""
77+
image_size = os.stat(raw).st_size
78+
image = f'{self.meta["name"]}-{self.meta["ostree-version"]}'
79+
image_description = f'{self.meta["name"]} {self.meta["summary"]} {self.meta["ostree-version"]}'
80+
81+
params = {
82+
'os': os.path.basename(raw).split("-")[0],
83+
'basearch': get_basearch(),
84+
'image_description': image_description,
85+
'image': image,
86+
'image_size': str(image_size),
87+
}
88+
89+
return params
90+
91+
def write_ova(self, image_name):
92+
"""
93+
write_ova file.
94+
95+
:param image_name: name of image to create OVF parameters for.
96+
:type image_name: str
97+
"""
98+
ovf_params = self.generate_ovf_parameters(image_name)
99+
100+
with open(OVA_TEMPLATE_FILE) as f:
101+
template = f.read()
102+
ovf_xml = template.format(**ovf_params)
103+
104+
meta_text = template_meta.format(**ovf_params)
105+
106+
with open(self.ovf_path, "w") as ovf:
107+
ovf.write(ovf_xml)
108+
109+
with open(self.meta_path, "w") as meta:
110+
meta.write(meta_text)
111+
112+
log.debug(ovf_xml)
113+
# OVF descriptor must come first, then the manifest, then the meta file
114+
self.tar_members.append(self.ovf_path)
115+
self.tar_members.append(self.meta_path)
116+
117+
118+
@retry(reraise=True, stop=stop_after_attempt(3))
119+
def ibmcloud_run_ore(build, args):
120+
ore_args = ['ore']
121+
if args.log_level:
122+
ore_args.extend(['--log-level', args.log_level])
123+
124+
if args.force:
125+
ore_args.extend(['--force'])
126+
127+
region = "us-east"
128+
if args.region is not None and len(args.region) > 0:
129+
region = args.region[0]
130+
131+
platform = args.target
132+
if args.cloud_object_storage is not None:
133+
cloud_object_storage = args.cloud_object_storage
134+
else:
135+
cloud_object_storage = f"coreos-dev-image-{platform}"
136+
137+
# powervs requires the image name to have an extension and also does not tolerate dots in the name. It affects the internal import from IBMCloud to the PowerVS systems
138+
if platform == "powervs":
139+
build_id = build.build_id.replace(".", "-") + ".ova"
140+
else:
141+
build_id = build.build_id
142+
143+
ibmcloud_object_name = f"{build.build_name}-{build_id}"
144+
ore_args.extend([
145+
'ibmcloud', 'upload',
146+
'--region', f"{region}",
147+
'--cloud-object-storage', f"{cloud_object_storage}",
148+
'--bucket', f"{args.bucket}",
149+
'--name', ibmcloud_object_name,
150+
'--file', f"{build.image_path}",
151+
])
152+
153+
run_verbose(ore_args)
154+
url_path = urllib.parse.quote((
155+
f"s3.{region}.cloud-object-storage.appdomain.cloud/"
156+
f"{args.bucket}/{ibmcloud_object_name}"
157+
))
158+
159+
build.meta[platform] = {
160+
'image': ibmcloud_object_name,
161+
'bucket': args.bucket,
162+
'region': region,
163+
'url': f"https://{url_path}",
164+
}
165+
build.meta_write() # update build metadata
166+
167+
168+
def ibmcloud_run_ore_replicate(build, args):
169+
pass
170+
171+
172+
def ibmcloud_cli(parser):
173+
parser.add_argument("--bucket", help="S3 Bucket")
174+
parser.add_argument("--cloud-object-storage", help="IBMCloud cloud object storage to upload to")
175+
return parser
176+
177+
178+
def get_ibmcloud_variant(variant, parser, kwargs={}):
179+
"""
180+
Helper function to get the IBMCloudImage Build Obj
181+
"""
182+
log.debug(f"returning IBMCloudImage for {variant}")
183+
return IBMCloudImage(
184+
buildroot=parser.buildroot,
185+
build=parser.build,
186+
schema=parser.schema,
187+
variant=variant,
188+
force=parser.force,
189+
**kwargs)

‎src/cosalib/qemuvariants.py

-5
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,6 @@
9090
"--format=oldgnu"
9191
]
9292
},
93-
"ibmcloud": {
94-
"image_format": "qcow2",
95-
"platform": "ibmcloud",
96-
"virtual_size": "100G",
97-
},
9893
"openstack": {
9994
"image_format": "qcow2",
10095
"platform": "openstack",

‎src/powervs-template.xml

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ovf:Envelope xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3+
<ovf:References>
4+
<ovf:File href="disk.raw" id="file1" size="{image_size}"/>
5+
</ovf:References>
6+
<ovf:DiskSection>
7+
<ovf:Info>Disk Section</ovf:Info>
8+
<ovf:Disk capacity="128849018880" capacityAllocationUnits="byte" diskId="disk1" fileRef="file1"/>
9+
</ovf:DiskSection>
10+
<ovf:VirtualSystemCollection>
11+
<ovf:VirtualSystem ovf:id="vs0">
12+
<ovf:Name>{image}</ovf:Name>
13+
<ovf:Info></ovf:Info>
14+
<ovf:ProductSection>
15+
<ovf:Info/>
16+
<ovf:Product/>
17+
</ovf:ProductSection>
18+
<ovf:OperatingSystemSection ovf:id="79">
19+
<ovf:Info/>
20+
<ovf:Description>{image_description}</ovf:Description>
21+
<ns0:architecture xmlns:ns0="ibmpvc">ppc64le</ns0:architecture>
22+
</ovf:OperatingSystemSection>
23+
<ovf:VirtualHardwareSection>
24+
<ovf:Info>Storage resources</ovf:Info>
25+
<ovf:Item>
26+
<rasd:Description>Temporary clone for export</rasd:Description>
27+
<rasd:ElementName>disk.raw</rasd:ElementName>
28+
<rasd:HostResource>ovf:/disk/disk1</rasd:HostResource>
29+
<rasd:InstanceID>1</rasd:InstanceID>
30+
<rasd:ResourceType>17</rasd:ResourceType>
31+
<ns1:boot xmlns:ns1="ibmpvc">True</ns1:boot>
32+
</ovf:Item>
33+
</ovf:VirtualHardwareSection>
34+
</ovf:VirtualSystem>
35+
<ovf:Info/>
36+
<ovf:Name>{image}</ovf:Name>
37+
</ovf:VirtualSystemCollection>
38+
</ovf:Envelope>

0 commit comments

Comments
 (0)
Please sign in to comment.