1
0
mirror of https://github.com/lxc/pylxd.git synced 2026-02-05 06:45:53 +01:00
Files
pylxd/migration/testing.py
2025-11-19 13:00:56 -05:00

157 lines
5.2 KiB
Python

# Copyright (c) 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import random
import string
import unittest
import uuid
from integration.busybox import create_busybox_image
from pylxd import exceptions
from pylxd.client import Client
class IntegrationTestCase(unittest.TestCase):
"""A base test case for pylxd integration tests."""
def setUp(self):
super().setUp()
self.client = Client()
self.lxd = self.client.api
def generate_object_name(self):
"""Generate a random object name."""
# Underscores are not allowed in container names.
test = self.id().split(".")[-1].replace("_", "")
rando = str(uuid.uuid1()).split("-")[-1]
return f"{test}-{rando}"
def create_container(self):
"""Create a container in lxd."""
fingerprint, alias = self.create_image()
name = self.generate_object_name()
machine = {
"name": name,
"architecture": "2",
"profiles": ["default"],
"ephemeral": False,
"config": {"limits.cpu": "2"},
"source": {"type": "image", "alias": alias},
}
result = self.lxd["containers"].post(json=machine)
operation_uuid = result.json()["operation"].split("/")[-1]
result = self.lxd.operations[operation_uuid].wait.get()
self.addCleanup(self.delete_container, name)
return name
def delete_container(self, name, enforce=False):
"""Delete a container in lxd."""
# enforce is a hack. There's a race somewhere in the delete.
# To ensure we don't get an infinite loop, let's count.
count = 0
try:
result = self.lxd["containers"][name].delete()
except exceptions.LXDAPIException as e:
if e.response.status_code in (400, 404):
return
raise
while enforce and result.status_code == 404 and count < 10:
try:
result = self.lxd["containers"][name].delete()
except exceptions.LXDAPIException as e:
if e.response.status_code in (400, 404):
return
raise
count += 1
try:
operation_uuid = result.json()["operation"].split("/")[-1]
result = self.lxd.operations[operation_uuid].wait.get()
except KeyError:
pass # 404 cases are okay.
def create_image(self):
"""Create an image in lxd."""
path, fingerprint = create_busybox_image()
with open(path, "rb") as f:
headers = {
"X-LXD-Public": "1",
}
response = self.lxd.images.post(data=f.read(), headers=headers)
operation_uuid = response.json()["operation"].split("/")[-1]
self.lxd.operations[operation_uuid].wait.get()
alias = self.generate_object_name()
response = self.lxd.images.aliases.post(
json={"description": "", "target": fingerprint, "name": alias}
)
self.addCleanup(self.delete_image, fingerprint)
return fingerprint, alias
def delete_image(self, fingerprint):
"""Delete an image in lxd."""
try:
self.lxd.images[fingerprint].delete()
except exceptions.LXDAPIException as e:
if e.response.status_code == 404:
return
raise
def create_profile(self):
"""Create a profile."""
name = self.generate_object_name()
config = {"limits.memory": "1GB"}
self.lxd.profiles.post(json={"name": name, "config": config})
return name
def delete_profile(self, name):
"""Delete a profile."""
try:
self.lxd.profiles[name].delete()
except exceptions.LXDAPIException as e:
if e.response.status_code == 404:
return
raise
def create_network(self):
# get interface name in format xxx0
name = "".join(random.sample(string.ascii_lowercase, 3)) + "0"
self.lxd.networks.post(
json={
"name": name,
"config": {},
}
)
return name
def delete_network(self, name):
try:
self.lxd.networks[name].delete()
except exceptions.NotFound:
pass
def assertCommon(self, response):
"""Assert common LXD responses.
LXD responses are relatively standard. This function makes assertions
to all those standards.
"""
response_json = response.json()
self.assertEqual(response.status_code, response_json["status_code"])
self.assertEqual(
["metadata", "operation", "status", "status_code", "type"],
sorted(response_json.keys()),
)