blob: ee1354ff80ee7e2db5d05fce8b2541529c004e6d [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
""" P1 tests for VM Schedule
"""
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.base import Account, ServiceOffering, VirtualMachine, VMSchedule
from marvin.lib.common import get_domain, get_zone, get_template
from marvin.lib.utils import cleanup_resources
# Import Local Modules
from nose.plugins.attrib import attr
import datetime
import time
class Services:
"""Test Snapshots Services"""
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "Test",
"lastname": "User",
"username": "test",
# Random characters are appended for unique
# username
"password": "password",
},
"service_offering": {
"name": "Tiny Instance",
"displaytext": "Tiny Instance",
"cpunumber": 1,
"cpuspeed": 200, # in MHz
"memory": 256, # In MBs
},
"disk_offering": {
"displaytext": "Small Disk",
"name": "Small Disk",
"disksize": 1,
},
"server": {
"displayname": "TestVM",
"username": "root",
"password": "password",
"ssh_port": 22,
"privateport": 22,
"publicport": 22,
"protocol": "TCP",
},
"mgmt_server": {
"ipaddress": "192.168.100.21",
"username": "root",
"password": "password",
"port": 22,
},
"templates": {
"displaytext": "Template",
"name": "Template",
"ostype": "CentOS 5.3 (64-bit)",
"templatefilter": "self",
},
"ostype": "CentOS 5.3 (64-bit)",
}
class TestVMSchedule(cloudstackTestCase):
@classmethod
def setUpClass(cls):
cls.testClient = super(TestVMSchedule, cls).getClsTestClient()
cls.api_client = cls.testClient.getApiClient()
cls._cleanup = []
cls.hypervisor = cls.testClient.getHypervisorInfo()
cls.services = Services().services
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
cls.services["mode"] = cls.zone.networktype
template = get_template(cls.api_client, cls.zone.id, cls.services["ostype"])
cls.services["domainid"] = cls.domain.id
cls.services["server"]["zoneid"] = cls.zone.id
cls.services["templates"]["ostypeid"] = template.ostypeid
cls.services["zoneid"] = cls.zone.id
# Create VMs, NAT Rules etc
cls.account = Account.create(
cls.api_client, cls.services["account"], domainid=cls.domain.id
)
cls._cleanup.append(cls.account)
cls.services["account"] = cls.account.name
cls.service_offering = ServiceOffering.create(
cls.api_client, cls.services["service_offering"]
)
cls._cleanup.append(cls.service_offering)
cls.virtual_machine = VirtualMachine.create(
cls.api_client,
cls.services["server"],
templateid=template.id,
accountid=cls.account.name,
domainid=cls.account.domainid,
serviceofferingid=cls.service_offering.id,
)
return
@classmethod
def tearDownClass(cls):
super(TestVMSchedule, cls).tearDownClass()
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
super(TestVMSchedule, self).tearDown()
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_01_vmschedule_create(self):
"""Test VM Schedule Creation in cron format and validate responses"""
# Validate the following
# 1. Create VM Schedule in cron format
# 2. List VM Schedule and verify the response
# 3. Delete VM Schedule and verify the response
# Create VM Schedule
schedule = "0 0 1 * *"
vmschedule = VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
schedule,
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
enabled=True,
)
self.cleanup.append(vmschedule)
self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
# List VM Schedule
vmschedules = VMSchedule.list(
self.apiclient, self.virtual_machine.id, id=vmschedule.id
)
self.assertEqual(
isinstance(vmschedules, list),
True,
"Check list response returns a valid list",
)
self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule list")
self.debug("List VM Schedule response: %s" % vmschedules[0].__dict__)
self.assertEqual(
vmschedules[0].id,
vmschedule.id,
"Check VM Schedule ID in list resources call",
)
self.assertEqual(
vmschedules[0].virtualmachineid,
self.virtual_machine.id,
"Check VM ID in list resources call",
)
self.assertEqual(
vmschedules[0].schedule,
schedule,
"Check VM Schedule in list resources call",
)
self.assertEqual(
vmschedules[0].timezone,
str(datetime.datetime.now().astimezone().tzinfo),
"Check VM Schedule timezone in list resources call",
)
# Check for entry in vm_scheduled_job in db
vmscheduled_job = self.dbclient.execute(
"select * from vm_scheduled_job where vm_schedule_id IN (SELECT id FROM vm_schedule WHERE uuid = '%s')"
% vmschedule.id,
db="cloud",
)
self.assertIsInstance(
vmscheduled_job,
list,
"Check if VM Schedule exists in vm_scheduled_job table",
)
self.assertGreater(
len(vmscheduled_job),
0,
"Check if VM Schedule exists in vm_scheduled_job table",
)
return
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_02_vmschedule_create_parameter_exceptions(self):
"""Test VM Schedule Creation exceptions with invalid parameters"""
# Validate the following
# 1. Create VM Schedule with invalid virtual machine ID
# 2. Create VM Schedule with invalid schedule
# 3. Create VM Schedule with invalid start date
# 5. Create VM Schedule with invalid action
# 6. Create VM Schedule with invalid end date
# Create VM Schedule with invalid virtual machine ID
with self.assertRaises(Exception):
VMSchedule.create(
self.apiclient,
"invalid",
"start",
"0 0 1 * *",
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
# Create VM Schedule with invalid schedule
with self.assertRaises(Exception):
VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
"invalid",
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
# Create VM Schedule with invalid start date
with self.assertRaises(Exception):
VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
"0 0 1 * *",
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
"invalid",
)
# Create VM Schedule with invalid action
with self.assertRaises(Exception):
VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"invalid",
"0 0 1 * *",
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
# test invalid end date
with self.assertRaises(Exception):
VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
"0 0 1 * *",
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
enddate="invalid",
)
return
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_03_vmschedule_update(self):
"""Test VM Schedule Update in cron format and validate responses"""
# Validate the following
# 1. Create VM Schedule in cron format
# 2. Update VM Schedule and verify the response
# Create VM Schedule
schedule = "0 0 1 * *"
vmschedule = VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
schedule,
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
self.cleanup.append(vmschedule)
self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
# Update VM Schedule
new_schedule = "0 0 2 * *"
vmschedule.update(
self.apiclient,
id=vmschedule.id,
virtualmachineid=self.virtual_machine.id,
description="TestVM",
schedule=new_schedule,
timezone=datetime.datetime.now().astimezone().tzinfo,
startdate=(
datetime.datetime.now() + datetime.timedelta(minutes=10)
).strftime("%Y-%m-%d %H:%M:%S"),
enddate=(datetime.datetime.now() + datetime.timedelta(hours=10)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
self.debug("Updated VM Schedule with ID: %s" % vmschedule.id)
# List VM Schedule
vmschedules = VMSchedule.list(
self.apiclient, self.virtual_machine.id, id=vmschedule.id
)
self.assertEqual(
isinstance(vmschedules, list),
True,
"Check list response returns a valid list",
)
self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule list")
self.debug("List VM Schedule response: %s" % vmschedules[0].__dict__)
self.assertEqual(
vmschedules[0].id,
vmschedule.id,
"Check VM Schedule ID in list resources call",
)
self.assertEqual(
vmschedules[0].virtualmachineid,
self.virtual_machine.id,
"Check VM ID in list resources call",
)
self.assertEqual(
vmschedules[0].schedule,
new_schedule,
"Check VM Schedule in list resources call",
)
return
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_04_vmschedule_update_parameter_exceptions(self):
"""Test VM Schedule Update exceptions with invalid parameters"""
# Validate the following
# 1. Update VM Schedule with invalid schedule
# 2. Update VM Schedule with invalid start date
# 3. Update VM Schedule with invalid ID
# 4. Update VM Schedule with invalid end date
# Create VM Schedule
schedule = "0 0 1 * *"
vmschedule = VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
schedule,
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
self.cleanup.append(vmschedule)
self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
# Update VM Schedule with invalid schedule
with self.assertRaises(Exception):
vmschedule.update(
self.apiclient,
id=vmschedule.id,
virtualmachineid=self.virtual_machine.id,
description="TestVM",
schedule="invalid",
timezone=datetime.datetime.now().astimezone().tzinfo,
startdate=(
datetime.datetime.now() + datetime.timedelta(minutes=5)
).strftime("%Y-%m-%d %H:%M:%S"),
)
# Update VM Schedule with invalid start date
with self.assertRaises(Exception):
vmschedule.update(
self.apiclient,
id=vmschedule.id,
virtualmachineid=self.virtual_machine.id,
description="TestVM",
schedule=schedule,
timezone=datetime.datetime.now().astimezone().tzinfo,
startdate=(
datetime.datetime.now() - datetime.timedelta(days=1)
).strftime("%Y-%m-%d %H:%M:%S"),
)
# Update VM Schedule with invalid ID
with self.assertRaises(Exception):
vmschedule.update(
self.apiclient,
id="invalid",
virtualmachineid=self.virtual_machine.id,
description="TestVM",
schedule=schedule,
timezone=datetime.datetime.now().astimezone().tzinfo,
startdate=(
datetime.datetime.now() + datetime.timedelta(minutes=5)
).strftime("%Y-%m-%d %H:%M:%S"),
)
# Update VM Schedule with invalid end date
with self.assertRaises(Exception):
vmschedule.update(
self.apiclient,
id=vmschedule.id,
virtualmachineid=self.virtual_machine.id,
description="TestVM",
schedule=schedule,
timezone=datetime.datetime.now().astimezone().tzinfo,
startdate=(
datetime.datetime.now() + datetime.timedelta(minutes=5)
).strftime("%Y-%m-%d %H:%M:%S"),
enddate=(
datetime.datetime.now() - datetime.timedelta(minutes=5)
).strftime("%Y-%m-%d %H:%M:%S"),
)
return
@attr(tags=["advanced", "basic"], required_hardware="false")
def test_05_vmschedule_test_e2e(self):
# Validate the following
# 1. Create 2 VM Schedules - start and stop
# 2. Verify VM Schedule is created
# 3. Verify VM is stopped after schedule time
# 4. Verify VM is started after schedule time
# 5. Delete VM Schedule
# 6. Verify VM Schedule is deleted
# 7. Verify VM is not stopped after schedule time
# 8. Verify VM is not started after schedule time
# Create VM Schedule - start
start_schedule = "*/2 * * * *"
start_vmschedule = VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"start",
start_schedule,
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(seconds=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
enabled=True,
)
self.debug("Created VM Schedule with ID: %s" % start_vmschedule.id)
# Create VM Schedule - stop
stop_schedule = "*/1 * * * *"
stop_vmschedule = VMSchedule.create(
self.apiclient,
self.virtual_machine.id,
"stop",
stop_schedule,
datetime.datetime.now().astimezone().tzinfo,
# Current date minutes in format "2014-01-01 00:00:00"
(datetime.datetime.now() + datetime.timedelta(seconds=5)).strftime(
"%Y-%m-%d %H:%M:%S"
),
enabled=True,
)
self.debug("Created VM Schedule with ID: %s" % stop_vmschedule.id)
# Verify VM Schedule is created
vmschedules = VMSchedule.list(
self.apiclient, self.virtual_machine.id, id=start_vmschedule.id
)
self.assertEqual(
isinstance(vmschedules, list),
True,
"Check list response returns a valid list",
)
self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule is created")
# poll every 10 seconds (max waiting time is 6 minutes) and check VM's state for changes
previous_state = self.virtual_machine.state
self.debug("VM state: %s" % self.virtual_machine.state)
is_stop_schedule_working = False
is_start_schedule_working = False
for i in range(0, 36):
time.sleep(10)
current_state = self.virtual_machine.update(self.apiclient).state
self.debug("Polling VM state: %s" % current_state)
if previous_state in ("Running", "Starting") and current_state in (
"Stopped",
"Stopping",
):
is_stop_schedule_working = True
elif previous_state in ("Stopped", "Stopping") and current_state in (
"Running",
"Starting",
):
is_start_schedule_working = True
if is_start_schedule_working and is_stop_schedule_working:
break
previous_state = current_state
self.debug("Is stop schedule working: %s" % is_stop_schedule_working)
self.debug("Is start schedule working: %s" % is_start_schedule_working)
self.assertTrue(
is_stop_schedule_working,
"VM switched states from Running to Stopped at least once",
)
self.assertTrue(
is_start_schedule_working,
"VM switched states from Stopped to Running at least once",
)
# Delete VM Schedule
start_vmschedule.delete(self.apiclient)
stop_vmschedule.delete(self.apiclient)
# To ensure that all vm schedules have been deleted and all of their jobs have been completed
time.sleep(60)
# Verify VM Schedule is deleted
self.assertEqual(
VMSchedule.list(
self.apiclient, self.virtual_machine.id, id=start_vmschedule.id
),
None,
"Check VM Schedule is deleted",
)
self.assertEqual(
VMSchedule.list(
self.apiclient, self.virtual_machine.id, id=stop_vmschedule.id
),
None,
"Check VM Schedule is deleted",
)
# Verify VM does not switch states after deleting schedules at least for 2 minutes
previous_state = self.virtual_machine.update(self.apiclient).state
state_changed = False
for i in range(0, 4):
time.sleep(30)
current_state = self.virtual_machine.update(self.apiclient).state
if previous_state != current_state:
# Add these checks because VMs can take some time to start or stop
if (previous_state == 'Starting' and current_state in ('Starting', 'Running')) or (
previous_state == 'Stopping' and current_state in ('Stopping', 'Stopped')):
continue
self.debug(
"VM changed state from %s to %s" % (previous_state, current_state)
)
state_changed = True
break
self.assertFalse(
state_changed,
"VM did not switch states after schedule time",
)
return