1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2012 Hewlett-Packard Development Company, L.P.
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
18
# Virtual power driver
20
from oslo.config import cfg
22
from nova import exception
23
from nova.openstack.common import importutils
24
from nova.openstack.common import log as logging
25
from nova import utils
26
from nova.virt.baremetal import baremetal_states
27
from nova.virt.baremetal import base
28
import nova.virt.powervm.common as connection
31
cfg.StrOpt('virtual_power_ssh_host',
33
help='ip or name to virtual power host'),
34
cfg.StrOpt('virtual_power_type',
36
help='base command to use for virtual power(vbox,virsh)'),
37
cfg.StrOpt('virtual_power_host_user',
39
help='user to execute virtual power commands as'),
40
cfg.StrOpt('virtual_power_host_pass',
42
help='password for virtual power host_user'),
45
baremetal_vp = cfg.OptGroup(name='baremetal',
46
title='Baremetal Options')
49
CONF.register_group(baremetal_vp)
50
CONF.register_opts(opts, baremetal_vp)
53
_virtual_power_settings = None
57
LOG = logging.getLogger(__name__)
60
class VirtualPowerManager(base.PowerManager):
61
"""Virtual Power Driver for Baremetal Nova Compute
63
This PowerManager class provides mechanism for controlling the power state
64
of VMs based on their name and MAC address. It uses ssh to connect to the
65
VM's host and issue commands.
67
Node will be matched based on mac address
69
NOTE: for use in dev/test environments only!
72
def __init__(self, **kwargs):
74
global _virtual_power_settings
78
LOG.debug("Setting up %s commands." %
79
CONF.baremetal.virtual_power_type)
80
_vpc = 'nova.virt.baremetal.virtual_power_driver_settings.%s' % \
81
CONF.baremetal.virtual_power_type
82
_cmds = importutils.import_class(_vpc)
83
self._vp_cmd = _cmds()
84
self.connection_data = _conn
85
node = kwargs.pop('node', {})
86
instance = kwargs.pop('instance', {})
87
self._node_name = instance.get('hostname', "")
88
self._mac_address = node.get('prov_mac_address', "")
89
self._mac_address = self._mac_address.replace(':', '')
90
self._connection = None
91
self._matched_name = ''
95
if not CONF.baremetal.virtual_power_ssh_host:
96
raise exception.NovaException(
97
_('virtual_power_ssh_host not defined. Can not Start'))
99
if not CONF.baremetal.virtual_power_host_user:
100
raise exception.NovaException(
101
_('virtual_power_host_user not defined. Can not Start'))
103
if not CONF.baremetal.virtual_power_host_pass:
104
raise exception.NovaException(
105
_('virtual_power_host_pass not defined. Can not Start'))
107
_conn = connection.Connection(
108
CONF.baremetal.virtual_power_ssh_host,
109
CONF.baremetal.virtual_power_host_user,
110
CONF.baremetal.virtual_power_host_pass)
113
def _set_connection(self):
114
if self._connection is None:
115
if self.connection_data is None:
116
self.connection_data = self._get_conn()
118
self._connection = connection.ssh_connect(self.connection_data)
120
def _get_full_node_list(self):
121
LOG.debug("Getting full node list.")
122
cmd = self._vp_cmd.list_cmd
123
full_list = self._run_command(cmd)
126
def _check_for_node(self):
127
LOG.debug("Looking up Name for Mac address %s." % self._mac_address)
128
self._matched_name = ''
129
full_node_list = self._get_full_node_list()
131
for node in full_node_list:
132
cmd = self._vp_cmd.get_node_macs.replace('{_NodeName_}', node)
133
mac_address_list = self._run_command(cmd)
135
for mac in mac_address_list:
136
if self._mac_address.lower() in mac.lower():
137
self._matched_name = node
139
if self._matched_name:
141
return self._matched_name
143
def activate_node(self):
144
LOG.info("activate_node name %s" % self._node_name)
145
if self._check_for_node():
146
cmd = self._vp_cmd.start_cmd
147
self._run_command(cmd)
149
if self.is_power_on():
150
self.state = baremetal_states.ACTIVE
152
self.state = baremetal_states.ERROR
155
def reboot_node(self):
156
LOG.info("reset node: %s" % self._node_name)
157
if self._check_for_node():
158
cmd = self._vp_cmd.reboot_cmd
159
self._run_command(cmd)
160
if self.is_power_on():
161
self.state = baremetal_states.ACTIVE
163
self.state = baremetal_states.ERROR
166
def deactivate_node(self):
167
LOG.info("deactivate_node name %s" % self._node_name)
168
if self._check_for_node():
169
if self.is_power_on():
170
cmd = self._vp_cmd.stop_cmd
171
self._run_command(cmd)
173
if self.is_power_on():
174
self.state = baremetal_states.ERROR
176
self.state = baremetal_states.DELETED
179
def is_power_on(self):
180
LOG.debug("Checking if %s is running" % self._node_name)
182
if not self._check_for_node():
185
cmd = self._vp_cmd.list_running_cmd
186
running_node_list = self._run_command(cmd)
188
for node in running_node_list:
189
if self._matched_name in node:
193
def start_console(self):
196
def stop_console(self):
199
def _run_command(self, cmd, check_exit_code=True):
200
"""Run a remote command using an active ssh connection.
202
:param command: String with the command to run.
204
If {_NodeName_} is in the command it will get replaced by
205
the _matched_name value.
207
base_cmd will also get prepended to the command.
209
self._set_connection()
211
cmd = cmd.replace('{_NodeName_}', self._matched_name)
213
cmd = '%s %s' % (self._vp_cmd.base_cmd, cmd)
216
stdout, stderr = utils.ssh_execute(self._connection, cmd,
217
check_exit_code=check_exit_code)
218
result = stdout.strip().splitlines()
219
LOG.debug('Result for run_command: %s' % result)
220
except exception.ProcessExecutionError:
222
LOG.exception("Error running command: %s" % cmd)