Merge ~mreed8855/plainbox-provider-checkbox:lxd-vm-virtualization into plainbox-provider-checkbox:master

Proposed by Michael Reed
Status: Rejected
Rejected by: Michael Reed
Proposed branch: ~mreed8855/plainbox-provider-checkbox:lxd-vm-virtualization
Merge into: plainbox-provider-checkbox:master
Diff against target: 276 lines (+230/-1)
3 files modified
bin/virtualization.py (+214/-0)
units/virtualization/jobs.pxu (+14/-0)
units/virtualization/test-plan.pxu (+2/-1)
Reviewer Review Type Date Requested Status
Jeff Lane  Needs Fixing
Review via email: mp+416851@code.launchpad.net

Commit message

This create a test for Virtual machines using LXD. This is related to the following merge proposal.

https://code.launchpad.net/~mreed8855/plainbox-provider-certification-server/+git/plainbox-provider-certification-server/+merge/416852

To post a comment you must log in.
Revision history for this message
Jeff Lane  (bladernr) wrote :

Inline comment below about the test plan for virtualization...
I'll try to play with this later.

review: Needs Fixing
Revision history for this message
Michael Reed (mreed8855) wrote :

Unmerged commits

7bc65c2... by Michael Reed

Adding a test to start and verify virtual machines using lxd

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/virtualization.py b/bin/virtualization.py
2index a3794de..75144e1 100755
3--- a/bin/virtualization.py
4+++ b/bin/virtualization.py
5@@ -865,6 +865,211 @@ class LXDTest(object):
6 return True
7
8
9+class LXDTest_vm(object):
10+
11+ def __init__(self, template=None, image=None):
12+ self.image_url = image
13+ self.template_url = template
14+ self.image_tarball = None
15+ self.template_tarball = None
16+ self.name = 'testbed'
17+ self.image_alias = uuid4().hex
18+ self.default_remote = "ubuntu:"
19+ self.os_version = get_release_to_test()
20+
21+ def run_command(self, cmd):
22+ task = RunCommand(cmd)
23+ if task.returncode != 0:
24+ logging.error('Command {} returnd a code of {}'.format(
25+ task.cmd, task.returncode))
26+ logging.error(' STDOUT: {}'.format(task.stdout))
27+ logging.error(' STDERR: {}'.format(task.stderr))
28+ return False
29+ else:
30+ logging.debug('Command {}:'.format(task.cmd))
31+ if task.stdout != '':
32+ logging.debug(' STDOUT: {}'.format(task.stdout))
33+ elif task.stderr != '':
34+ logging.debug(' STDERR: {}'.format(task.stderr))
35+ else:
36+ logging.debug(' Command returned no output')
37+ return True
38+
39+ def setup(self):
40+ # Initialize LXD
41+ result = True
42+ logging.debug("Attempting to initialize LXD")
43+ # TODO: Need a method to see if LXD is already initialized
44+ if not self.run_command('lxd init --auto'):
45+ logging.debug('Error encounterd while initializing LXD')
46+ result = False
47+
48+ # Retrieve and insert LXD images
49+ if self.template_url is not None:
50+ logging.debug("Downloading template.")
51+ targetfile = urlparse(self.template_url).path.split('/')[-1]
52+ filename = os.path.join('/tmp', targetfile)
53+ if not os.path.isfile(filename):
54+ self.template_tarball = self.download_images(self.template_url,
55+ filename)
56+ if not self.template_tarball:
57+ logging.error("Unable to download {} from "
58+ "{}".format(self.template_tarball,
59+ self.template_url))
60+ logging.error("Aborting")
61+ result = False
62+ else:
63+ logging.debug("Template file {} already exists. "
64+ "Skipping Download.".format(filename))
65+ self.template_tarball = filename
66+
67+ if self.image_url is not None:
68+ logging.debug("Downloading image.")
69+ targetfile = urlparse(self.image_url).path.split('/')[-1]
70+ filename = os.path.join('/tmp', targetfile)
71+ if not os.path.isfile(filename):
72+ self.image_tarball = self.download_images(self.image_url,
73+ filename)
74+ if not self.image_tarball:
75+ logging.error("Unable to download {} from{}".format(
76+ self.image_tarball, self.image_url))
77+ logging.error("Aborting")
78+ result = False
79+ else:
80+ logging.debug("Template file {} already exists. "
81+ "Skipping Download.".format(filename))
82+ self.image_tarball = filename
83+
84+ # Insert images
85+ if self.template_url is not None and self.image_url is not None:
86+ logging.debug("Importing images into LXD")
87+ cmd = 'lxc image import {} {} --alias {}'.format(
88+ self.template_tarball, self.image_tarball,
89+ self.image_alias)
90+ result = self.run_command(cmd)
91+ if not result:
92+ logging.error('Error encountered while attempting to '
93+ 'import images into LXD')
94+ result = False
95+ return result
96+
97+ def download_images(self, url, filename):
98+ """
99+ Downloads LXD files for same release as host machine
100+ """
101+ # TODO: Clean this up to use a non-internet simplestream on MAAS server
102+ logging.debug("Attempting download of {} from {}".format(filename,
103+ url))
104+ try:
105+ urllib.request.urlretrieve(url, filename)
106+ except (IOError,
107+ OSError,
108+ urllib.error.HTTPError,
109+ urllib.error.URLError) as exception:
110+ logging.error("Failed download of image from %s: %s",
111+ url, exception)
112+ return False
113+ except ValueError as verr:
114+ logging.error("Invalid URL %s" % url)
115+ logging.error("%s" % verr)
116+ return False
117+
118+ if not os.path.isfile(filename):
119+ logging.warn("Can not find {}".format(filename))
120+ return False
121+
122+ return filename
123+
124+ def cleanup(self):
125+ """
126+ Clean up test files an Virtual Machines created
127+ """
128+ logging.debug('Cleaning up images and VMs created during test')
129+ self.run_command('lxc image delete {}'.format(self.image_alias))
130+ self.run_command('lxc delete --force {}'.format(self.name))
131+
132+ def start_vm(self):
133+ """
134+ Creates an lxd virtutal machine and performs the test
135+ """
136+ wait_interval = 5
137+ test_interval = 300
138+
139+ result = self.setup()
140+ if not result:
141+ logging.error("One or more setup stages failed.")
142+ return False
143+
144+ # Create Virtual Machine
145+ logging.debug("Launching Virtual Machine")
146+ if not self.image_url and not self.template_url:
147+ logging.debug("No local image available, attempting to "
148+ "import from default remote.")
149+ cmd = ('lxc init {}{} {} --vm '.format(
150+ self.default_remote, self.os_version, self.name))
151+ else:
152+ cmd = ('lxc init {} {} --vm'.format(self.image_alias, self.name))
153+
154+ if not self.run_command(cmd):
155+ return False
156+
157+ logging.debug("Start VM:")
158+ cmd = ("lxc start {} ".format(self.name))
159+ if not self.run_command(cmd):
160+ return False
161+
162+ logging.debug("Virtual Machine listing:")
163+ cmd = ("lxc list")
164+ if not self.run_command(cmd):
165+ return False
166+
167+ logging.debug("Wait for vm to boot")
168+ check_vm = 0
169+ while check_vm < test_interval:
170+ time.sleep(wait_interval)
171+ cmd = ("lxc exec {} -- lsb_release -a".format(self.name))
172+ if self.run_command(cmd):
173+ print("Vm started and booted succefully")
174+ return True
175+ else:
176+ logging.debug("Re-verify VM booted")
177+ check_vm = check_vm + wait_interval
178+
179+ logging.debug("testing vm failed")
180+ if check_vm == test_interval:
181+ return False
182+
183+
184+def test_lxd_vm(args):
185+ logging.debug("Executing LXD VM Test")
186+
187+ template = None
188+ image = None
189+
190+ # First in priority are environment variables.
191+ if 'LXD_TEMPLATE' in os.environ:
192+ template = os.environ['LXD_TEMPLATE']
193+ if 'KVM_IMAGE' in os.environ:
194+ image = os.environ['KVM_IMAGE']
195+
196+ # Finally, highest-priority are command line arguments.
197+ if args.template:
198+ template = args.template
199+ if args.image:
200+ image = args.image
201+
202+ lxd_test = LXDTest_vm(template, image)
203+
204+ result = lxd_test.start_vm()
205+ lxd_test.cleanup()
206+ if result:
207+ print("PASS: Virtual Machine was succssfully started and checked")
208+ sys.exit(0)
209+ else:
210+ print("FAIL: Virtual Machine was not started and checked")
211+ sys.exit(1)
212+
213+
214 def test_uvtkvm(args):
215 logging.debug("Executing UVT KVM Test")
216 # if args.image is not set and UVT_IMAGE_OR_SOURCE does not exist, a key
217@@ -965,6 +1170,8 @@ def main():
218 'uvt', help=("Run uvt kvm virtualization test"))
219 lxd_test_parser = subparsers.add_parser(
220 'lxd', help=("Run the LXD validation test"))
221+ lxd_test_vm_parser = subparsers.add_parser(
222+ 'lxdvm', help=("Run the LXD VM validation test"))
223 parser.add_argument('--debug', dest='log_level',
224 action="store_const", const=logging.DEBUG,
225 default=logging.INFO)
226@@ -990,6 +1197,13 @@ def main():
227 '--rootfs', type=str, default=None)
228 lxd_test_parser.set_defaults(func=test_lxd)
229
230+ # Sub test options
231+ lxd_test_vm_parser.add_argument(
232+ '--template', type=str, default=None)
233+ lxd_test_vm_parser.add_argument(
234+ '--image', type=str, default=None)
235+ lxd_test_vm_parser.set_defaults(func=test_lxd_vm)
236+
237 args = parser.parse_args()
238
239 try:
240diff --git a/units/virtualization/jobs.pxu b/units/virtualization/jobs.pxu
241index 2b903c7..54fb496 100644
242--- a/units/virtualization/jobs.pxu
243+++ b/units/virtualization/jobs.pxu
244@@ -19,6 +19,20 @@ _summary:
245
246 plugin: shell
247 category_id: com.canonical.plainbox::virtualization
248+id: virtualization/verify_lxd_vm
249+environ: LXD_TEMPLATE KVM_IMAGE
250+estimated_duration: 60.0
251+requires:
252+ executable.name == 'lxc'
253+ package.name == 'lxd' or snap.name == 'lxd'
254+command: virtualization.py --debug lxdvm
255+_description:
256+ Verifies that an LXD Virtual Machine can be created and launched
257+_summary:
258+ Verify LXD Virtual Machine launches
259+
260+plugin: shell
261+category_id: com.canonical.plainbox::virtualization
262 id: virtualization/verify_lxd
263 environ: LXD_TEMPLATE LXD_ROOTFS
264 estimated_duration: 30.0
265diff --git a/units/virtualization/test-plan.pxu b/units/virtualization/test-plan.pxu
266index 16f4c73..9bd31b6 100644
267--- a/units/virtualization/test-plan.pxu
268+++ b/units/virtualization/test-plan.pxu
269@@ -16,4 +16,5 @@ unit: test plan
270 _name: Automated virtualization tests
271 include:
272 virtualization/kvm_check_vm
273- virtualization/verify_lxd
274\ No newline at end of file
275+ virtualization/verify_lxd
276+ virtualization/verify_lxd_vm

Subscribers

People subscribed via source and target branches