If use only one of --vcpu or --ram param in slave-change command,
other param won't use default value and won't change VM
Change-Id: Ie1e37d1083a1f860d1b03d8c75af3500201c2f67
Closes-bug: #1464649
262 lines
8.7 KiB
Python
262 lines
8.7 KiB
Python
# Copyright 2013 - 2015 Mirantis, Inc.
|
|
#
|
|
# 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 json
|
|
|
|
from django.conf import settings
|
|
from django.db import models
|
|
|
|
from devops.helpers.helpers import _tcp_ping
|
|
from devops.helpers.helpers import _wait
|
|
from devops.helpers.helpers import SSHClient
|
|
from devops.models.base import choices
|
|
from devops.models.base import DriverModel
|
|
|
|
|
|
class NodeManager(models.Manager):
|
|
def create(self, *args, **kwargs):
|
|
Node.node_create(*args, **kwargs)
|
|
|
|
def all(self, *args, **kwargs):
|
|
Node.objects.all()
|
|
|
|
|
|
class Node(DriverModel):
|
|
class Meta:
|
|
unique_together = ('name', 'environment')
|
|
db_table = 'devops_node'
|
|
|
|
environment = models.ForeignKey('Environment', null=True)
|
|
name = models.CharField(max_length=255, unique=False, null=False)
|
|
uuid = models.CharField(max_length=255)
|
|
hypervisor = choices('kvm')
|
|
os_type = choices('hvm')
|
|
architecture = choices('x86_64', 'i686')
|
|
boot = models.CharField(max_length=255, null=False, default=json.dumps([]))
|
|
metadata = models.CharField(max_length=255, null=True)
|
|
role = models.CharField(max_length=255, null=True)
|
|
vcpu = models.PositiveSmallIntegerField(null=False, default=1)
|
|
memory = models.IntegerField(null=False, default=1024)
|
|
has_vnc = models.BooleanField(null=False, default=True)
|
|
|
|
def next_disk_name(self):
|
|
disk_names = ('sd' + c for c in list('abcdefghijklmnopqrstuvwxyz'))
|
|
while True:
|
|
disk_name = disk_names.next()
|
|
if not self.disk_devices.filter(target_dev=disk_name).exists():
|
|
return disk_name
|
|
|
|
def get_vnc_port(self):
|
|
return self.driver.node_get_vnc_port(node=self)
|
|
|
|
@property
|
|
def disk_devices(self):
|
|
return self.diskdevice_set.all()
|
|
|
|
@property
|
|
def interfaces(self):
|
|
return self.interface_set.order_by('id')
|
|
|
|
@property
|
|
def vnc_password(self):
|
|
return settings.VNC_PASSWORD
|
|
|
|
def interface_by_name(self, name):
|
|
self.interfaces.filter(name=name)
|
|
|
|
def get_ip_address_by_network_name(self, name, interface=None):
|
|
interface = interface or self.interface_set.filter(
|
|
network__name=name).order_by('id')[0]
|
|
return interface.address_set.get(interface=interface).ip_address
|
|
|
|
def remote(self, network_name, login, password=None, private_keys=None):
|
|
"""Create SSH-connection to the network
|
|
|
|
:rtype : SSHClient
|
|
"""
|
|
return SSHClient(
|
|
self.get_ip_address_by_network_name(network_name),
|
|
username=login,
|
|
password=password, private_keys=private_keys)
|
|
|
|
def send_keys(self, keys):
|
|
self.driver.node_send_keys(self, keys)
|
|
|
|
def await(self, network_name, timeout=120, by_port=22):
|
|
_wait(
|
|
lambda: _tcp_ping(
|
|
self.get_ip_address_by_network_name(network_name), by_port),
|
|
timeout=timeout)
|
|
|
|
def define(self):
|
|
self.driver.node_define(self)
|
|
self.save()
|
|
|
|
def start(self):
|
|
self.create(verbose=False)
|
|
|
|
def create(self, verbose=False):
|
|
if verbose or not self.driver.node_active(self):
|
|
self.driver.node_create(self)
|
|
|
|
def destroy(self, verbose=False):
|
|
if verbose or self.driver.node_active(self):
|
|
self.driver.node_destroy(self)
|
|
|
|
def erase(self):
|
|
self.remove(verbose=False)
|
|
|
|
def remove(self, verbose=False):
|
|
if verbose or self.uuid:
|
|
if verbose or self.driver.node_exists(self):
|
|
self.destroy(verbose=False)
|
|
self.driver.node_undefine(self, undefine_snapshots=True)
|
|
self.delete()
|
|
|
|
def suspend(self, verbose=False):
|
|
if verbose or self.driver.node_active(self):
|
|
self.driver.node_suspend(self)
|
|
|
|
def resume(self, verbose=False):
|
|
if verbose or self.driver.node_active(self):
|
|
self.driver.node_resume(self)
|
|
|
|
def has_snapshot(self, name):
|
|
return self.driver.node_snapshot_exists(node=self, name=name)
|
|
|
|
def snapshot(self, name=None, force=False, description=None):
|
|
if force and self.has_snapshot(name):
|
|
self.driver.node_delete_snapshot(node=self, name=name)
|
|
self.driver.node_create_snapshot(
|
|
node=self, name=name, description=description)
|
|
|
|
def revert(self, name=None, destroy=True):
|
|
if destroy:
|
|
self.destroy(verbose=False)
|
|
if self.has_snapshot(name):
|
|
self.driver.node_revert_snapshot(node=self, name=name)
|
|
else:
|
|
print('Domain snapshot for {0} node not found: no domain '
|
|
'snapshot with matching'
|
|
' name {1}'.format(self.name, name))
|
|
|
|
def get_snapshots(self):
|
|
"""Return full snapshots objects"""
|
|
return self.driver.node_get_snapshots(node=self)
|
|
|
|
def erase_snapshot(self, name):
|
|
self.driver.node_delete_snapshot(node=self, name=name)
|
|
|
|
def set_vcpu(self, vcpu):
|
|
"""Set vcpu count on node
|
|
|
|
param: vcpu: Integer
|
|
:rtype : None
|
|
"""
|
|
if vcpu is not None and vcpu != self.vcpu:
|
|
self.vcpu = vcpu
|
|
self.driver.node_set_vcpu(node=self, vcpu=vcpu)
|
|
self.save()
|
|
|
|
def set_memory(self, memory):
|
|
"""Set memory size on node
|
|
|
|
param: memory: Integer
|
|
:rtype : None
|
|
"""
|
|
if memory is not None and memory != self.memory:
|
|
self.memory = memory
|
|
self.driver.node_set_memory(node=self, memory=memory * 1024)
|
|
self.save()
|
|
|
|
def attach_to_networks(self, network_names=None):
|
|
"""Attache node to several networks
|
|
|
|
|
|
param: network_names: List
|
|
:rtype : None
|
|
"""
|
|
if network_names is None:
|
|
network_names = settings.DEFAULT_INTERFACE_ORDER.split(',')
|
|
networks = [
|
|
self.environment.get_network(name=n) for n in network_names]
|
|
self.environment.create_interfaces(networks=networks,
|
|
node=self)
|
|
|
|
def attach_disks(self,
|
|
disknames_capacity=None,
|
|
format='qcow2', device='disk', bus='virtio',
|
|
force_define=False):
|
|
"""Attach several disks to node
|
|
|
|
|
|
param: disknames_capacity: Dict
|
|
param: format: String
|
|
param: device: String
|
|
param: bus: String
|
|
param: force_define: Bool
|
|
:rtype : None
|
|
"""
|
|
if disknames_capacity is None:
|
|
disknames_capacity = {
|
|
'system': 50 * 1024 ** 3,
|
|
'swift': 50 * 1024 ** 3,
|
|
'cinder': 50 * 1024 ** 3,
|
|
}
|
|
|
|
for diskname, capacity in disknames_capacity.iteritems():
|
|
self.attach_disk(name=diskname,
|
|
capacity=capacity,
|
|
force_define=force_define)
|
|
|
|
def attach_disk(self, name, capacity, format='qcow2',
|
|
device='disk', bus='virtio', force_define=False):
|
|
"""Attach disk to node
|
|
|
|
|
|
param: disknames_capacity: Dict
|
|
param: format: String
|
|
param: device: String
|
|
param: bus: String
|
|
param: force_define: Bool
|
|
:rtype : DiskDevice
|
|
"""
|
|
vol_name = "%s-%s" % (self.name, name)
|
|
disk = self.environment.add_empty_volume(node=self,
|
|
name=vol_name,
|
|
capacity=capacity,
|
|
device=device,
|
|
bus=bus)
|
|
if force_define:
|
|
disk.volume.define()
|
|
return disk
|
|
|
|
@classmethod
|
|
def node_create(cls, name, environment=None, role=None, vcpu=1,
|
|
memory=1024, has_vnc=True, metadata=None, hypervisor='kvm',
|
|
os_type='hvm', architecture='x86_64', boot=None):
|
|
"""Create node
|
|
|
|
:rtype : Node
|
|
"""
|
|
if not boot:
|
|
boot = ['network', 'cdrom', 'hd']
|
|
node = cls.objects.create(
|
|
name=name, environment=environment,
|
|
role=role, vcpu=vcpu, memory=memory,
|
|
has_vnc=has_vnc, metadata=metadata, hypervisor=hypervisor,
|
|
os_type=os_type, architecture=architecture, boot=json.dumps(boot)
|
|
)
|
|
return node
|