~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to nova/virt/baremetal/virtual_power_driver.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Adam Gandelman
  • Date: 2013-02-22 09:27:29 UTC
  • mfrom: (1.1.68)
  • Revision ID: package-import@ubuntu.com-20130222092729-nn3gt8rf97uvts77
Tags: 2013.1.g3-0ubuntu1
[ Chuck Short ]
* New usptream release. 
* debian/patches/debian/patches/fix-ubuntu-tests.patch: Refreshed.
* debian/nova-baremetal.logrotate: Fix logfile path.
* debian/control, debian/nova-spiceproxy.{install, logrotate, upstart}:
  Add spice html5 proxy support.
* debian/nova-novncproxy.upstart: Start on runlevel [2345]
* debian/rules: Call testr directly since run_tests.sh -N gives weird return
  value when tests pass.
* debian/pyddist-overrides: Add websockify.
* debian/nova-common.postinst: Removed config file conversion, since
  the option is no longer available. (LP: #1110567)
* debian/control: Add python-pyasn1 as a dependency.
* debian/control: Add python-oslo-config as a dependency.
* debian/control: Suggest sysfsutils, sg3-utils, multipath-tools for fibre
  channel support.

[ Adam Gandelman ]
* debian/control: Fix typo (websocikfy -> websockify).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2012 Hewlett-Packard Development Company, L.P.
 
4
# All Rights Reserved.
 
5
#
 
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
 
9
#
 
10
#         http://www.apache.org/licenses/LICENSE-2.0
 
11
#
 
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
 
16
#    under the License.
 
17
#
 
18
# Virtual power driver
 
19
 
 
20
from oslo.config import cfg
 
21
 
 
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
 
29
 
 
30
opts = [
 
31
    cfg.StrOpt('virtual_power_ssh_host',
 
32
               default='',
 
33
               help='ip or name to virtual power host'),
 
34
    cfg.StrOpt('virtual_power_type',
 
35
               default='vbox',
 
36
               help='base command to use for virtual power(vbox,virsh)'),
 
37
    cfg.StrOpt('virtual_power_host_user',
 
38
               default='',
 
39
               help='user to execute virtual power commands as'),
 
40
    cfg.StrOpt('virtual_power_host_pass',
 
41
               default='',
 
42
               help='password for virtual power host_user'),
 
43
]
 
44
 
 
45
baremetal_vp = cfg.OptGroup(name='baremetal',
 
46
                            title='Baremetal Options')
 
47
 
 
48
CONF = cfg.CONF
 
49
CONF.register_group(baremetal_vp)
 
50
CONF.register_opts(opts, baremetal_vp)
 
51
 
 
52
_conn = None
 
53
_virtual_power_settings = None
 
54
_vp_cmd = None
 
55
_cmds = None
 
56
 
 
57
LOG = logging.getLogger(__name__)
 
58
 
 
59
 
 
60
class VirtualPowerManager(base.PowerManager):
 
61
    """Virtual Power Driver for Baremetal Nova Compute
 
62
 
 
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.
 
66
 
 
67
    Node will be matched based on mac address
 
68
 
 
69
    NOTE: for use in dev/test environments only!
 
70
 
 
71
    """
 
72
    def __init__(self, **kwargs):
 
73
        global _conn
 
74
        global _virtual_power_settings
 
75
        global _cmds
 
76
 
 
77
        if _cmds is None:
 
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 = ''
 
92
        self.state = None
 
93
 
 
94
    def _get_conn(self):
 
95
        if not CONF.baremetal.virtual_power_ssh_host:
 
96
            raise exception.NovaException(
 
97
                _('virtual_power_ssh_host not defined. Can not Start'))
 
98
 
 
99
        if not CONF.baremetal.virtual_power_host_user:
 
100
            raise exception.NovaException(
 
101
                _('virtual_power_host_user not defined. Can not Start'))
 
102
 
 
103
        if not CONF.baremetal.virtual_power_host_pass:
 
104
            raise exception.NovaException(
 
105
                _('virtual_power_host_pass not defined. Can not Start'))
 
106
 
 
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)
 
111
        return _conn
 
112
 
 
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()
 
117
 
 
118
            self._connection = connection.ssh_connect(self.connection_data)
 
119
 
 
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)
 
124
        return full_list
 
125
 
 
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()
 
130
 
 
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)
 
134
 
 
135
            for mac in mac_address_list:
 
136
                if self._mac_address.lower() in mac.lower():
 
137
                    self._matched_name = node
 
138
                    break
 
139
            if self._matched_name:
 
140
                break
 
141
        return self._matched_name
 
142
 
 
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)
 
148
 
 
149
        if self.is_power_on():
 
150
            self.state = baremetal_states.ACTIVE
 
151
        else:
 
152
            self.state = baremetal_states.ERROR
 
153
        return self.state
 
154
 
 
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
 
162
        else:
 
163
            self.state = baremetal_states.ERROR
 
164
        return self.state
 
165
 
 
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)
 
172
 
 
173
        if self.is_power_on():
 
174
            self.state = baremetal_states.ERROR
 
175
        else:
 
176
            self.state = baremetal_states.DELETED
 
177
        return self.state
 
178
 
 
179
    def is_power_on(self):
 
180
        LOG.debug("Checking if %s is running" % self._node_name)
 
181
 
 
182
        if not self._check_for_node():
 
183
            return False
 
184
 
 
185
        cmd = self._vp_cmd.list_running_cmd
 
186
        running_node_list = self._run_command(cmd)
 
187
 
 
188
        for node in running_node_list:
 
189
            if self._matched_name in node:
 
190
                return True
 
191
        return False
 
192
 
 
193
    def start_console(self):
 
194
        pass
 
195
 
 
196
    def stop_console(self):
 
197
        pass
 
198
 
 
199
    def _run_command(self, cmd, check_exit_code=True):
 
200
        """Run a remote command using an active ssh connection.
 
201
 
 
202
        :param command: String with the command to run.
 
203
 
 
204
        If {_NodeName_} is in the command it will get replaced by
 
205
        the _matched_name value.
 
206
 
 
207
        base_cmd will also get prepended to the command.
 
208
        """
 
209
        self._set_connection()
 
210
 
 
211
        cmd = cmd.replace('{_NodeName_}', self._matched_name)
 
212
 
 
213
        cmd = '%s %s' % (self._vp_cmd.base_cmd, cmd)
 
214
 
 
215
        try:
 
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:
 
221
            result = []
 
222
            LOG.exception("Error running command: %s" % cmd)
 
223
        return result