Skip to content

Commit

Permalink
feat: VM Import Test Cases
Browse files Browse the repository at this point in the history
* introduce vm-import test cases with OpenStack LTS

Resolves harvester#522
  • Loading branch information
irishgordo committed May 9, 2023
1 parent 110d360 commit 9a38a0e
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 1 deletion.
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ node-scripts-location: 'scripts/vagrant'
# URL to download the Windows image
win-image-url: ''
opensuse-image-url: https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.3/images/openSUSE-Leap-15.3.x86_64-NoCloud.qcow2
# Jammy by default
# Jammy is needed for OpenStack integration tests as Focal is not supported by OpenStack microstack
ubuntu-image-url: https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64-disk-kvm.img
# URL to download all images
image-cache-url: ''

Expand Down
6 changes: 6 additions & 0 deletions harvester_e2e_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ def pytest_addoption(parser):
default=config_data.get('opensuse-image-url'),
help=('OpenSUSE image URL')
)
parser.addoption(
'--ubuntu-image-url',
action='store',
default=config_data.get('ubuntu-image-url'),
help=('Ubuntu image URL')
)
parser.addoption(
'--terraform-scripts-location',
action='store',
Expand Down
15 changes: 14 additions & 1 deletion harvester_e2e_tests/fixtures/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# TODO: remove it after update CI's config.yml
DEFAULT_OPENSUSE_IMAGE_URL = ("https://download.opensuse.org/repositories/Cloud:/Images:"
"/Leap_15.3/images/openSUSE-Leap-15.3.x86_64-NoCloud.qcow2")

DEFAULT_JAMMY_IMAGE_URL = "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64-disk-kvm.img"

@pytest.fixture(scope="session")
def image_opensuse(request, api_client):
Expand All @@ -23,6 +23,19 @@ def image_opensuse(request, api_client):
return ImageInfo(url, ssh_user='opensuse')


# needed for openstack, as openstack impl only works with jammy
@pytest.fixture(scope="session")
def image_jammy(request, api_client):
image_server = request.config.getoption('--image-cache-url')
url = urlparse(request.config.getoption('--ubuntu-image-url') or DEFAULT_JAMMY_IMAGE_URL)

if image_server:
*_, image_name = url.path.rsplit('/', 1)
url = urlparse(urljoin(f"{image_server}/", image_name))

return ImageInfo(url, ssh_user='ubuntu')


class ImageInfo:
def __init__(self, url_result, ssh_user=None):
self.url_result = url_result
Expand Down
59 changes: 59 additions & 0 deletions harvester_e2e_tests/fixtures/vm_imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) 2023 SUSE LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 3 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.
#
# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com
from harvester_e2e_tests import utils
import pytest
import os

from datetime import datetime, timedelta
from time import sleep


@pytest.fixture(scope='module')
def user_data_openstack():
# set to root user password to 'linux' to test password login in
# addition to SSH login
yaml_data = """#cloud-config
chpasswd:
list: |
root:linux
expire: false
ssh_pwauth: true
users:
- name: root
package_update: true
packages:
- qemu-guest-agent
snap:
commands:
- snap install microstack --devmode --beta
- snap alias microstack.openstack openstack
- snap set microstack config.credentials.keystone-password=testtesttest
runcmd:
- - systemctl
- enable
- '--now'
- qemu-ga
- echo fs.inotify.max_queued_events=1048576 | tee -a /etc/sysctl.conf
- echo fs.inotify.max_user_instances=1048576 | tee -a /etc/sysctl.conf
- echo fs.inotify.max_user_watches=1048576 | tee -a /etc/sysctl.conf
- echo vm.max_map_count=262144 | tee -a /etc/sysctl.conf
- echo vm.swappiness=1 | tee -a /etc/sysctl.conf
- sysctl -p
- microstack init --auto --control --setup-loop-based-cinder-lvm-backend --loop-device-file-size 50
- snap restart microstack.cinder-{uwsgi,scheduler,volume}
"""
return yaml_data.replace('\n', '\\n')
166 changes: 166 additions & 0 deletions harvester_e2e_tests/integration/test_vm_imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Copyright (c) 2021 SUSE LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 3 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.
#
# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

import pytest
from harvester_e2e_tests import utils
from datetime import datetime, timedelta
from pathlib import Path
from tempfile import NamedTemporaryFile
from time import sleep

import json
import re
import pytest
import yaml
from paramiko.ssh_exception import ChannelException

pytest_plugins = [
'harvester_e2e_tests.fixtures.api_client',
'harvester_e2e_tests.fixtures.vm_imports',
'harvester_e2e_tests.fixtures.images',
'harvester_e2e_tests.fixtures.virtualmachines'
]


@pytest.fixture(scope="session")
def virtctl(api_client):
code, ctx = api_client.vms.download_virtctl()

with NamedTemporaryFile("wb") as f:
f.write(ctx)
f.seek(0)
yield Path(f.name)


@pytest.fixture(scope="session")
def kubeconfig_file(api_client):
kubeconfig = api_client.generate_kubeconfig()
with NamedTemporaryFile("w") as f:
f.write(kubeconfig)
f.seek(0)
yield Path(f.name)

@pytest.fixture(scope="module")
def image_ubuntu_jammy(api_client, image_jammy, unique_name, wait_timeout):
unique_image_id = f'image-{unique_name}'
code, data = api_client.images.create_by_url(
unique_image_id, image_jammy.url, display_name=f"{unique_name}-{image_jammy.name}"
)

assert 201 == code, (code, data)

endtime = datetime.now() + timedelta(seconds=wait_timeout)
while endtime > datetime.now():
code, data = api_client.images.get(unique_image_id)
if 100 == data.get('status', {}).get('progress', 0):
break
sleep(3)
else:
raise AssertionError(
"Failed to create Image with error:\n"
f"Status({code}): {data}"
)

yield dict(id=f"{data['metadata']['namespace']}/{unique_image_id}",
user=image_jammy.ssh_user)

code, data = api_client.images.delete(unique_image_id)


@pytest.fixture(scope="module")
def unique_vm_name(unique_name):
return f"vm-{unique_name}"

@pytest.fixture(scope="module")
def openstack_vm(api_client, image_ubuntu_jammy, unique_vm_name, wait_timeout, user_data_openstack):
"""
tbd...
"""
cpu, mem = 6, 12
vm = api_client.vms.Spec(cpu, mem, description="OpenStack VM", guest_agent=False)
vm.add_image("disk-0", image_ubuntu_jammy['id'])
vm.user_data = user_data_openstack

code, data = api_client.vms.create(unique_vm_name, vm)

assert 201 == code, (code, data)

endtime = datetime.now() + timedelta(seconds=wait_timeout)
while endtime > datetime.now():
code, data = api_client.vms.get_status(unique_vm_name)
if 200 == code and "Running" == data.get('status', {}).get('phase'):
break
sleep(3)
else:
raise AssertionError(
f"Failed to create OpenStack VM({cpu} core, {mem} RAM) with errors:\n"
f"Status: {data.get('status')}\n"
f"API Status({code}): {data}"
)

yield unique_vm_name

api_client.vms.delete(unique_vm_name)
endtime = datetime.now() + timedelta(seconds=wait_timeout)
while endtime > datetime.now():
code, data = api_client.vms.get_status(unique_vm_name)
if 404 == code:
break
sleep(3)


@pytest.mark.p0
class TestOpenStackSetup:

@pytest.mark.dependency(name="openstack_openrc")
def test_openstack_openrc(self, api_client, openstack_vm, wait_timeout, vm_shell):
"""
Test...
"""
# make sure the VM instance is successfully created
code, data = api_client.vms.get(openstack_vm)
assert 200 == code
assert "Running" == data['status']['printableStatus']
#vm_shell = vm_shell.login(data['status']['interfaces'][0]['ipAddress'], user="root", password="linux")
pass
# find some way to get clouds.yaml file https://192.168.9.90/project/api_access/clouds.yaml/
# This is a clouds.yaml file, which can be used by OpenStack tools as a source
# of configuration on how to connect to a cloud. If this is your only cloud,
# just put this file in ~/.config/openstack/clouds.yaml and tools like
# python-openstackclient will just work with no further config. (You will need
# to add your password to the auth section)
# If you have more than one cloud account, add the cloud entry to the clouds
# section of your existing file and you can refer to them by name with
# OS_CLOUD=openstack or --os-cloud=openstack
# clouds:
# openstack:
# auth:
# auth_url: https://192.168.9.90:5000/v3/
# username: "admin"
# project_id: 63c9628764e54f9a913af16c472bb7e8
# project_name: "admin"
# user_domain_name: "Default"
# region_name: "microstack"
# interface: "public"
# identity_api_version: 3
# ubuntu@node4:~$ openstack project list --user admin -f json
# [
# {
# "ID": "63c9628764e54f9a913af16c472bb7e8",
# "Name": "admin"
# }
# ]

0 comments on commit 9a38a0e

Please sign in to comment.