Some small improvements to pass pep8 and pep257.
This is just the first run. Change-Id: If47a475b03d367a4e04f54ef31845e70d46f188c
This commit is contained in:
parent
fb00359b51
commit
444ebaa26f
@ -0,0 +1,15 @@
|
||||
"""Common module for osha."""
|
||||
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
@ -1,4 +1,6 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
"""Manage all configuration the OpenStack way."""
|
||||
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -11,12 +13,15 @@
|
||||
# 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.
|
||||
from oslo_config import cfg
|
||||
from osha.common.utils import env
|
||||
import sys
|
||||
from osha import __version__ as OSHA_VERSION
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
from osha import __version__ as OSHA_VERSION
|
||||
from osha.common.utils import env
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
_MONITORS = [
|
||||
@ -32,11 +37,10 @@ _MONITORS = [
|
||||
cfg.DictOpt('kwargs',
|
||||
default={},
|
||||
help='List of kwargs if you want to pass it to initialize'
|
||||
' the monitoring driver. should be provided in key:value '
|
||||
'format')
|
||||
' the monitoring driver. should be provided in key:value '
|
||||
'format')
|
||||
]
|
||||
|
||||
|
||||
_COMMON = [
|
||||
cfg.IntOpt('wait',
|
||||
default=30,
|
||||
@ -46,93 +50,92 @@ _COMMON = [
|
||||
_FENCER = [
|
||||
cfg.StrOpt('credentials-file',
|
||||
help='YAML File contains the required credentials for compute '
|
||||
'nodes'),
|
||||
'nodes'),
|
||||
cfg.IntOpt('retries',
|
||||
default=1,
|
||||
help='Number of retries to fence the each compute node. Must be'
|
||||
' at least 1 to try first the soft shutdown'),
|
||||
' at least 1 to try first the soft shutdown'),
|
||||
cfg.IntOpt('hold-period',
|
||||
default=10,
|
||||
help='Time in seconds to wait between retries. Should be '
|
||||
'reasonable amount of time as different servers take '
|
||||
'different times to shut off'),
|
||||
'reasonable amount of time as different servers take '
|
||||
'different times to shut off'),
|
||||
cfg.StrOpt('driver',
|
||||
default='osha.fencers.drivers.ipmi.driver.IpmiDriver',
|
||||
help='Choose the best fencer driver i.e.(ipmi, libvirt, ..'),
|
||||
cfg.DictOpt('options',
|
||||
default={},
|
||||
help='List of kwargs to customize the fencer operation. You '
|
||||
'fencer driver should support these options. Options '
|
||||
'should be in key:value format')
|
||||
'fencer driver should support these options. Options '
|
||||
'should be in key:value format')
|
||||
]
|
||||
|
||||
_KEYSTONE_AUTH_TOKEN = [
|
||||
cfg.StrOpt('auth_uri',
|
||||
help='Openstack auth URI i.e. http://controller:5000',
|
||||
dest='auth_uri'),
|
||||
cfg.StrOpt('auth_url',
|
||||
help='Openstack auth URL i.e. http://controller:35357/v3',
|
||||
dest='auth_url'),
|
||||
dest='auth_uri'), cfg.StrOpt(
|
||||
'auth_url',
|
||||
help='Openstack auth URL i.e. http://controller:35357/v3',
|
||||
dest='auth_url'),
|
||||
cfg.StrOpt('auth_plugin',
|
||||
help='Openstack auth plugin i.e. ( password, token, ...) '
|
||||
'password is the only available plugin for the time being',
|
||||
dest='auth_plugin'),
|
||||
cfg.StrOpt('username',
|
||||
help='Openstack username',
|
||||
dest='username'),
|
||||
'password is the only available plugin for the time being',
|
||||
dest='auth_plugin'), cfg.StrOpt('username',
|
||||
help='Openstack username',
|
||||
dest='username'),
|
||||
cfg.StrOpt('password',
|
||||
help='Openstack Password',
|
||||
dest='password'),
|
||||
cfg.StrOpt('project_name',
|
||||
help='Openstack Project Name.',
|
||||
dest='project_name'),
|
||||
dest='password'), cfg.StrOpt('project_name',
|
||||
help='Openstack Project Name.',
|
||||
dest='project_name'),
|
||||
cfg.StrOpt('domain_name',
|
||||
help='Openstack domain Name.',
|
||||
dest='domain_name'),
|
||||
cfg.StrOpt('project_domain_id',
|
||||
help='Openstack Project Domain id, default is Default',
|
||||
dest='project_domain_id'),
|
||||
dest='domain_name'), cfg.StrOpt(
|
||||
'project_domain_id',
|
||||
help='Openstack Project Domain id, default is Default',
|
||||
dest='project_domain_id'),
|
||||
cfg.StrOpt('user_domain_id',
|
||||
help='Openstack user Domain id, default is Default',
|
||||
dest='user_domain_id'),
|
||||
cfg.StrOpt('project_domain_name',
|
||||
help='Openstack Project Domain name, default is Default',
|
||||
dest='project_domain_name'),
|
||||
cfg.StrOpt('user_domain_name',
|
||||
help='Openstack user Domain name, default is Default',
|
||||
dest='user_domain_name'),
|
||||
dest='user_domain_id'), cfg.StrOpt(
|
||||
'project_domain_name',
|
||||
help='Openstack Project Domain name, default is Default',
|
||||
dest='project_domain_name'), cfg.StrOpt(
|
||||
'user_domain_name',
|
||||
help='Openstack user Domain name, default is Default',
|
||||
dest='user_domain_name'),
|
||||
cfg.DictOpt('kwargs',
|
||||
help='Openstack Authentication arguments you can pass it here '
|
||||
'as Key:Value, Key1:Value1, ... ',
|
||||
'as Key:Value, Key1:Value1, ... ',
|
||||
dest='kwargs',
|
||||
default={})
|
||||
]
|
||||
|
||||
|
||||
_EVACUATION = [
|
||||
cfg.StrOpt('driver',
|
||||
default='osha.evacuators.drivers.osha.standard.'
|
||||
'OshaStandardEvacuator',
|
||||
help='Time in seconds to wait between retries to disable compute'
|
||||
' node or put it in maintenance mode. Default 10 seconds',
|
||||
dest='driver'),
|
||||
cfg.IntOpt('wait',
|
||||
default=10,
|
||||
help='Time in seconds to wait between retries to disable compute'
|
||||
' node or put it in maintenance mode. Default 10 seconds',
|
||||
dest='wait'),
|
||||
cfg.StrOpt(
|
||||
'driver',
|
||||
default='osha.evacuators.drivers.osha.standard.'
|
||||
'OshaStandardEvacuator',
|
||||
help='Time in seconds to wait between retries to disable compute'
|
||||
' node or put it in maintenance mode. Default 10 seconds',
|
||||
dest='driver'), cfg.IntOpt(
|
||||
'wait',
|
||||
default=10,
|
||||
help='Time in seconds to wait between retries to disable compute'
|
||||
' node or put it in maintenance mode. Default 10 seconds',
|
||||
dest='wait'),
|
||||
cfg.IntOpt('retries',
|
||||
default=1,
|
||||
help='Number of retries to put node in maintenance mode before '
|
||||
'reporting failure to evacuate the node',
|
||||
'reporting failure to evacuate the node',
|
||||
dest='retries'),
|
||||
cfg.DictOpt('options',
|
||||
default={},
|
||||
help='Dict contains kwargs to be passed to the evacuator driver'
|
||||
'. In case you have additional args needs to be passed to '
|
||||
'your evacuator please, list them as key0:value0, '
|
||||
'key1:value1, ....',
|
||||
dest='options')
|
||||
cfg.DictOpt(
|
||||
'options',
|
||||
default={},
|
||||
help='Dict contains kwargs to be passed to the evacuator driver'
|
||||
'. In case you have additional args needs to be passed to '
|
||||
'your evacuator please, list them as key0:value0, '
|
||||
'key1:value1, ....',
|
||||
dest='options')
|
||||
]
|
||||
|
||||
_NOTIFIERS = [
|
||||
@ -140,121 +143,124 @@ _NOTIFIERS = [
|
||||
default='osha.notifiers.drivers.osha.default_email.OshaEmail',
|
||||
dest='driver',
|
||||
help='Notification driver to load it to notify users '
|
||||
'if something went wrong'),
|
||||
'if something went wrong'),
|
||||
cfg.StrOpt('endpoint',
|
||||
default=None,
|
||||
dest='endpoint',
|
||||
help='Endpoint URL for the notification system. If you the '
|
||||
'driver you are using doesnot require any URL just comment '
|
||||
'it or use none'),
|
||||
cfg.StrOpt('username',
|
||||
default=None,
|
||||
dest='username',
|
||||
help='Username to authenticate against the notification system. '
|
||||
'If the driver you are using doesnot require any '
|
||||
'authentications comment or use None'),
|
||||
cfg.StrOpt('password',
|
||||
default=None,
|
||||
dest='password',
|
||||
help='Password to authenticate against the notification system. '
|
||||
'If the driver you are using doesnot require any '
|
||||
'authentications comment or use None'),
|
||||
'driver you are using doesnot require any URL just comment '
|
||||
'it or use none'),
|
||||
cfg.StrOpt(
|
||||
'username',
|
||||
default=None,
|
||||
dest='username',
|
||||
help='Username to authenticate against the notification system. '
|
||||
'If the driver you are using doesnot require any '
|
||||
'authentications comment or use None'), cfg.StrOpt(
|
||||
'password',
|
||||
default=None,
|
||||
dest='password',
|
||||
help='Password to authenticate against the notification system. '
|
||||
'If the driver you are using doesnot require any '
|
||||
'authentications comment or use None'),
|
||||
cfg.StrOpt('templates-dir',
|
||||
dest='templates-dir',
|
||||
default='/etc/osha/templates',
|
||||
help='Path to Jinja2 templates directory that contains '
|
||||
'message templates'),
|
||||
'message templates'),
|
||||
cfg.DictOpt('options',
|
||||
default={},
|
||||
dest='options',
|
||||
help='Key:Value Kwargs to pass it to the notification driver, '
|
||||
'if you want to pass any special arguments for your '
|
||||
'driver. '),
|
||||
'if you want to pass any special arguments for your '
|
||||
'driver. '),
|
||||
cfg.ListOpt('notify-list',
|
||||
default=[],
|
||||
dest='notify-list',
|
||||
help='List of emails to sent them notification if something '
|
||||
'went wrong and Osha wasnot able to send an email to the '
|
||||
'tenant admin'),
|
||||
'went wrong and Osha wasnot able to send an email to the '
|
||||
'tenant admin'),
|
||||
cfg.StrOpt('notify-from',
|
||||
dest='notify-from',
|
||||
help='The sender address, it can be email address if we used '
|
||||
'default email driver, or phone number if we use sms '
|
||||
'gateway for example.')
|
||||
'default email driver, or phone number if we use sms '
|
||||
'gateway for example.')
|
||||
]
|
||||
|
||||
|
||||
def build_os_options():
|
||||
"""Build oslo options related to OpenStack environment."""
|
||||
osclient_opts = [
|
||||
cfg.StrOpt('os-username',
|
||||
default=env('OS_USERNAME'),
|
||||
help='Name used for authentication with the OpenStack '
|
||||
'Identity service. Defaults to env[OS_USERNAME].',
|
||||
'Identity service. Defaults to env[OS_USERNAME].',
|
||||
dest='os_username'),
|
||||
cfg.StrOpt('os-password',
|
||||
default=env('OS_PASSWORD'),
|
||||
help='Password used for authentication with the OpenStack '
|
||||
'Identity service. Defaults to env[OS_PASSWORD].',
|
||||
'Identity service. Defaults to env[OS_PASSWORD].',
|
||||
dest='os_password'),
|
||||
cfg.StrOpt('os-project-name',
|
||||
default=env('OS_PROJECT_NAME'),
|
||||
help='Project name to scope to. Defaults to '
|
||||
'env[OS_PROJECT_NAME].',
|
||||
'env[OS_PROJECT_NAME].',
|
||||
dest='os_project_name'),
|
||||
cfg.StrOpt('os-project-domain-name',
|
||||
default=env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help='Domain name containing project. Defaults to '
|
||||
'env[OS_PROJECT_DOMAIN_NAME].',
|
||||
'env[OS_PROJECT_DOMAIN_NAME].',
|
||||
dest='os_project_domain_name'),
|
||||
cfg.StrOpt('os-user-domain-name',
|
||||
default=env('OS_USER_DOMAIN_NAME'),
|
||||
help='User\'s domain name. Defaults to '
|
||||
'env[OS_USER_DOMAIN_NAME].',
|
||||
'env[OS_USER_DOMAIN_NAME].',
|
||||
dest='os_user_domain_name'),
|
||||
cfg.StrOpt('os-tenant-name',
|
||||
default=env('OS_TENANT_NAME'),
|
||||
help='Tenant to request authorization on. Defaults to '
|
||||
'env[OS_TENANT_NAME].',
|
||||
'env[OS_TENANT_NAME].',
|
||||
dest='os_tenant_name'),
|
||||
cfg.StrOpt('os-tenant-id',
|
||||
default=env('OS_TENANT_ID'),
|
||||
help='Tenant to request authorization on. Defaults to '
|
||||
'env[OS_TENANT_ID].',
|
||||
'env[OS_TENANT_ID].',
|
||||
dest='os_tenant_id'),
|
||||
cfg.StrOpt('os-auth-url',
|
||||
default=env('OS_AUTH_URL'),
|
||||
help='Specify the Identity endpoint to use for '
|
||||
'authentication. Defaults to env[OS_AUTH_URL].',
|
||||
'authentication. Defaults to env[OS_AUTH_URL].',
|
||||
dest='os_auth_url'),
|
||||
cfg.StrOpt('os-backup-url',
|
||||
default=env('OS_BACKUP_URL'),
|
||||
help='Specify the Freezer backup service endpoint to use. '
|
||||
'Defaults to env[OS_BACKUP_URL].',
|
||||
'Defaults to env[OS_BACKUP_URL].',
|
||||
dest='os_backup_url'),
|
||||
cfg.StrOpt('os-region-name',
|
||||
default=env('OS_REGION_NAME'),
|
||||
help='Specify the region to use. Defaults to '
|
||||
'env[OS_REGION_NAME].',
|
||||
'env[OS_REGION_NAME].',
|
||||
dest='os_region_name'),
|
||||
cfg.StrOpt('os-token',
|
||||
default=env('OS_TOKEN'),
|
||||
help='Specify an existing token to use instead of retrieving'
|
||||
' one via authentication (e.g. with username & '
|
||||
'password). Defaults to env[OS_TOKEN].',
|
||||
dest='os_token'),
|
||||
cfg.StrOpt(
|
||||
'os-token',
|
||||
default=env('OS_TOKEN'),
|
||||
help='Specify an existing token to use instead of retrieving'
|
||||
' one via authentication (e.g. with username & '
|
||||
'password). Defaults to env[OS_TOKEN].',
|
||||
dest='os_token'),
|
||||
cfg.StrOpt('os-identity-api-version',
|
||||
default=env('OS_IDENTITY_API_VERSION'),
|
||||
help='Identity API version: 2.0 or 3. '
|
||||
'Defaults to env[OS_IDENTITY_API_VERSION]',
|
||||
'Defaults to env[OS_IDENTITY_API_VERSION]',
|
||||
dest='os_identity_api_version'),
|
||||
cfg.StrOpt('os-endpoint-type',
|
||||
choices=['public', 'publicURL', 'internal', 'internalURL',
|
||||
'admin', 'adminURL'],
|
||||
default=env('OS_ENDPOINT_TYPE') or 'public',
|
||||
help='Endpoint type to select. Valid endpoint types: '
|
||||
'"public" or "publicURL", "internal" or "internalURL",'
|
||||
' "admin" or "adminURL". Defaults to '
|
||||
'env[OS_ENDPOINT_TYPE] or "public"',
|
||||
'"public" or "publicURL", "internal" or "internalURL",'
|
||||
' "admin" or "adminURL". Defaults to '
|
||||
'env[OS_ENDPOINT_TYPE] or "public"',
|
||||
dest='os_endpoint_type'),
|
||||
]
|
||||
|
||||
@ -262,19 +268,20 @@ def build_os_options():
|
||||
|
||||
|
||||
def configure():
|
||||
"""Register configuration."""
|
||||
CONF.register_cli_opts(build_os_options())
|
||||
CONF.register_opts(_COMMON)
|
||||
monitors_grp = cfg.OptGroup('monitoring',
|
||||
title='Monitoring',
|
||||
help='Monitoring Driver/plugin to be used to '
|
||||
'monitor compute nodes')
|
||||
'monitor compute nodes')
|
||||
CONF.register_group(monitors_grp)
|
||||
CONF.register_opts(_MONITORS, group='monitoring')
|
||||
|
||||
fencers_grp = cfg.OptGroup('fencer',
|
||||
title='fencer Options',
|
||||
help='fencer Driver/plugin to be used to '
|
||||
'fence compute nodes')
|
||||
title='fencer Options',
|
||||
help='fencer Driver/plugin to be used to '
|
||||
'fence compute nodes')
|
||||
CONF.register_group(fencers_grp)
|
||||
CONF.register_opts(_FENCER, group='fencer')
|
||||
|
||||
@ -282,16 +289,16 @@ def configure():
|
||||
evacuators_grp = cfg.OptGroup('evacuation',
|
||||
title='Evacuation Options',
|
||||
help='Evacuation Driver/plugin opts to be '
|
||||
'used to Evacuate compute nodes')
|
||||
'used to Evacuate compute nodes')
|
||||
CONF.register_group(evacuators_grp)
|
||||
CONF.register_opts(_EVACUATION, group='evacuation')
|
||||
|
||||
# Notification Section :)
|
||||
notifiers_grp = cfg.OptGroup('notifiers',
|
||||
title='Notification Options',
|
||||
help='Notification Driver/plugin opts to be '
|
||||
'used to Notify admins/users if failure '
|
||||
'happens')
|
||||
title='Notification Options',
|
||||
help='Notification Driver/plugin opts to be '
|
||||
'used to Notify admins/users if failure '
|
||||
'happens')
|
||||
CONF.register_group(notifiers_grp)
|
||||
CONF.register_opts(_NOTIFIERS, group='notifiers')
|
||||
|
||||
@ -299,32 +306,33 @@ def configure():
|
||||
keystone_grp = cfg.OptGroup('keystone_authtoken',
|
||||
title='Keystone Auth Options',
|
||||
help='Openstack Credentials to call the nova '
|
||||
'APIs to evacuate ')
|
||||
'APIs to evacuate ')
|
||||
CONF.register_group(keystone_grp)
|
||||
CONF.register_opts(_KEYSTONE_AUTH_TOKEN, group='keystone_authtoken')
|
||||
|
||||
default_conf = cfg.find_config_files('osha', 'osha',
|
||||
'.conf')
|
||||
default_conf = cfg.find_config_files('osha', 'osha', '.conf')
|
||||
log.register_options(CONF)
|
||||
|
||||
CONF(args=sys.argv[1:],
|
||||
project='osha',
|
||||
default_config_files=default_conf,
|
||||
version=OSHA_VERSION
|
||||
)
|
||||
version=OSHA_VERSION)
|
||||
|
||||
|
||||
def setup_logging():
|
||||
_DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN','qpid=WARN',
|
||||
'stevedore=WARN', 'oslo_log=INFO', 'iso8601=WARN',
|
||||
"""Set some oslo log defaults."""
|
||||
_DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN',
|
||||
'qpid=WARN', 'stevedore=WARN', 'oslo_log=INFO',
|
||||
'iso8601=WARN',
|
||||
'requests.packages.urllib3.connectionpool=WARN',
|
||||
'urllib3.connectionpool=WARN', 'websocket=WARN',
|
||||
'keystonemiddleware=WARN', 'osha=INFO']
|
||||
|
||||
_DEFAULT_LOGGING_CONTEXT_FORMAT = ('%(asctime)s.%(msecs)03d %(process)d '
|
||||
'%(levelname)s %(name)s [%(request_id)s '
|
||||
'%(user_identity)s] %(instance)s'
|
||||
'%(message)s')
|
||||
_DEFAULT_LOGGING_CONTEXT_FORMAT = (
|
||||
'%(asctime)s.%(msecs)03d %(process)d '
|
||||
'%(levelname)s %(name)s [%(request_id)s '
|
||||
'%(user_identity)s] %(instance)s'
|
||||
'%(message)s')
|
||||
log.set_defaults(_DEFAULT_LOGGING_CONTEXT_FORMAT, _DEFAULT_LOG_LEVELS)
|
||||
log.setup(CONF, 'osha', version=OSHA_VERSION)
|
||||
|
||||
@ -340,4 +348,3 @@ def list_opts():
|
||||
}
|
||||
|
||||
return _OPTS.items()
|
||||
|
||||
|
@ -1,165 +1,183 @@
|
||||
#!/usr/bin/env python
|
||||
"""Generic deamon."""
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 sys, os, time, atexit
|
||||
from signal import SIGTERM
|
||||
from __future__ import print_function
|
||||
|
||||
import atexit
|
||||
import logging as log
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from signal import SIGTERM
|
||||
|
||||
|
||||
class Daemon:
|
||||
class Daemon(object):
|
||||
|
||||
"""A generic daemon class.
|
||||
|
||||
Usage: subclass the Daemon class and override the run() method
|
||||
"""
|
||||
|
||||
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null',
|
||||
stderr='/dev/null'):
|
||||
"""Instantiantion."""
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.pidfile = pidfile
|
||||
|
||||
def daemonize(self):
|
||||
"""Do the UNIX double-fork magic.
|
||||
|
||||
See Stevens' "Advanced Programming in the UNIX Environment" for
|
||||
details (ISBN 0201563177)
|
||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||
"""
|
||||
A generic daemon class.
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError as e:
|
||||
sys.stderr.write("fork #1 failed: %d (%s)\n" %
|
||||
(e.errno, e.strerror))
|
||||
log.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
Usage: subclass the Daemon class and override the run() method
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError as e:
|
||||
sys.stderr.write("fork #2 failed: %d (%s)\n"
|
||||
% (e.errno, e.strerror))
|
||||
log.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
# redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = file(self.stdin, 'r')
|
||||
so = file(self.stdout, 'a+')
|
||||
se = file(self.stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# write pidfile
|
||||
atexit.register(self.delpid)
|
||||
|
||||
pid = str(os.getpid())
|
||||
f = file(self.pidfile, 'w+')
|
||||
f.write("%s\n" % pid)
|
||||
f.close()
|
||||
|
||||
def delpid(self):
|
||||
"""Delete PID file."""
|
||||
os.remove(self.pidfile)
|
||||
|
||||
def start(self):
|
||||
"""Start the daemon."""
|
||||
log.error("Test")
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exist. Daemon" \
|
||||
" already running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
self.run()
|
||||
|
||||
# @todo needs some enhancement like check /proc/%pid/status if it's
|
||||
# really running or not ! may be it's killed by external process
|
||||
# the PID won't be updated !
|
||||
def status(self):
|
||||
"""Check daemon status."""
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exist. Daemon already " \
|
||||
"running. PID: %d \n"
|
||||
sys.stdout.write(message % (self.pidfile, pid))
|
||||
sys.exit(0)
|
||||
else:
|
||||
message = "Service not running!\n"
|
||||
sys.stdout.write(message)
|
||||
sys.exit(0)
|
||||
|
||||
def stop(self):
|
||||
"""Stop the daemon."""
|
||||
# Get the pid from the pidfile
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if not pid:
|
||||
message = "pidfile %s does not exist." \
|
||||
" Daemon not running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
while 1:
|
||||
os.kill(pid, SIGTERM)
|
||||
time.sleep(0.1)
|
||||
except OSError as err:
|
||||
err = str(err)
|
||||
if err.find("No such process") > 0:
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
else:
|
||||
print(str(err))
|
||||
sys.exit(1)
|
||||
|
||||
def restart(self):
|
||||
"""Restart the daemon."""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
"""You should override this method when you subclass Daemon.
|
||||
|
||||
It will be called after the process has been
|
||||
daemonized by start() or restart().
|
||||
"""
|
||||
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null',
|
||||
stderr='/dev/null'):
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.pidfile = pidfile
|
||||
|
||||
def daemonize(self):
|
||||
"""
|
||||
do the UNIX double-fork magic, see Stevens' "Advanced
|
||||
Programming in the UNIX Environment" for details
|
||||
(ISBN 0201563177)
|
||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||
"""
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #1 failed: %d (%s)\n" %
|
||||
(e.errno, e.strerror))
|
||||
log.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #2 failed: %d (%s)\n"
|
||||
% (e.errno, e.strerror))
|
||||
log.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
# redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = file(self.stdin, 'r')
|
||||
so = file(self.stdout, 'a+')
|
||||
se = file(self.stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# write pidfile
|
||||
atexit.register(self.delpid)
|
||||
|
||||
pid = str(os.getpid())
|
||||
f = file(self.pidfile, 'w+')
|
||||
f.write("%s\n" % pid)
|
||||
f.close()
|
||||
|
||||
def delpid(self):
|
||||
os.remove(self.pidfile)
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the daemon
|
||||
"""
|
||||
log.error("Test")
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = file(self.pidfile,'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError as e:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exist. Daemon" \
|
||||
" already running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
self.run()
|
||||
|
||||
# @todo needs some enhancement like check /proc/%pid/status if it's
|
||||
# really running or not ! may be it's killed by external process
|
||||
# the PID won't be updated !
|
||||
def status(self):
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError as e:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exist. Daemon already " \
|
||||
"running. PID: %d \n"
|
||||
sys.stdout.write(message % (self.pidfile, pid))
|
||||
sys.exit(0)
|
||||
else:
|
||||
message = "Service not running !\n"
|
||||
sys.stdout.write(message)
|
||||
sys.exit(0)
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the daemon
|
||||
"""
|
||||
# Get the pid from the pidfile
|
||||
try:
|
||||
pf = file(self.pidfile,'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if not pid:
|
||||
message = "pidfile %s does not exist." \
|
||||
" Daemon not running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
while 1:
|
||||
os.kill(pid, SIGTERM)
|
||||
time.sleep(0.1)
|
||||
except OSError, err:
|
||||
err = str(err)
|
||||
if err.find("No such process") > 0:
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
else:
|
||||
print str(err)
|
||||
sys.exit(1)
|
||||
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the daemon
|
||||
"""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
You should override this method when you subclass Daemon.
|
||||
It will be called after the process has been
|
||||
daemonized by start() or restart().
|
||||
"""
|
@ -1,4 +1,5 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
"""OpenStack client class."""
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -11,21 +12,30 @@
|
||||
# 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.
|
||||
from __future__ import print_function
|
||||
|
||||
from keystoneclient import session
|
||||
|
||||
from keystoneclient.auth.identity import v3
|
||||
from keystoneclient import session
|
||||
from novaclient.v2 import client as novaclient
|
||||
from neutronclient.v2_0 import client as neutronclient
|
||||
|
||||
from keystoneclient.v3 import client as keystoneclient
|
||||
|
||||
from neutronclient.v2_0 import client as neutronclient
|
||||
|
||||
from novaclient.v2 import client as novaclient
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class OSClient:
|
||||
"""Provide OpenStack credentials to initalize the connection."""
|
||||
|
||||
def __init__(self, authurl, authmethod='password', ** kwargs):
|
||||
"""
|
||||
Provide Openstack credentials to initalize the connection to Openstack
|
||||
"""Initialize the all class vars.
|
||||
|
||||
:param authmethod: string authmethod should be password or token but
|
||||
currently we support only password !
|
||||
:param kwargs: username, user_id, project_name, project_id,
|
||||
@ -49,15 +59,17 @@ class OSClient:
|
||||
# self.user_id = kwargs.get('user_id', None)
|
||||
# self.user_domain_id = kwargs.get('user_domain_id', None)
|
||||
# self.user_domain_name = kwargs.get('user_domain_name', None)
|
||||
# self.project_domain_name = kwargs.get('project_domain_name', None)
|
||||
# self.project_domain_name =
|
||||
# kwargs.get('project_domain_name', None)
|
||||
# self.endpoint_type = kwargs.get('endpoint_type', 'internalURL')
|
||||
else:
|
||||
print "The available authmethod is password for the time being" \
|
||||
"Please, provide a password credentials :) "
|
||||
print("The available authmethod is password for the time being")
|
||||
print("Please, provide a password credential.")
|
||||
|
||||
self.auth()
|
||||
|
||||
def auth(self):
|
||||
"""Create a session."""
|
||||
auth = v3.Password(auth_url=self.authurl,
|
||||
**self.kwargs)
|
||||
self.auth_session = session.Session(auth=auth)
|
||||
@ -89,16 +101,16 @@ class OSClient:
|
||||
def neutronagents(self, hosts=[]):
|
||||
if not hosts:
|
||||
hosts = self.compute_hosts
|
||||
new_sess = session.Session(auth=self.auth_session.auth)
|
||||
neutron = neutronclient.Client(session=new_sess,
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
neutron = neutronclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
self.auth_session = new_sess
|
||||
self.auth_session = auth_session
|
||||
agents = neutron.list_agents()
|
||||
neutron_agents = []
|
||||
for agent in agents.get('agents'):
|
||||
if agent.get('host') in hosts and agent.get('binary') == \
|
||||
'neutron-openvswitch-agent':
|
||||
neutron_agents.append(agent)
|
||||
if agent.get('host') in hosts and agent.get('binary') == \
|
||||
'neutron-openvswitch-agent':
|
||||
neutron_agents.append(agent)
|
||||
|
||||
return neutron_agents
|
||||
|
||||
@ -109,10 +121,10 @@ class OSClient:
|
||||
:param nodes: List of nodes to be evacuated !
|
||||
:return: List of nodes with VMs that were running on that node
|
||||
"""
|
||||
new_sess = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=new_sess,
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
self.auth_session = new_sess
|
||||
self.auth_session = auth_session
|
||||
evacuated_nodes = []
|
||||
for node in nodes:
|
||||
hypervisors = nova.hypervisors.search(node.get('host'), True)
|
||||
@ -125,15 +137,17 @@ class OSClient:
|
||||
on_shared_storage=True)
|
||||
except Exception as e:
|
||||
LOG.error(e)
|
||||
host = {'host': node.get('host'), 'servers': hypervisor.servers}
|
||||
host = {'host': node.get(
|
||||
'host'), 'servers': hypervisor.servers}
|
||||
evacuated_nodes.append(host)
|
||||
return evacuated_nodes
|
||||
|
||||
def set_in_maintance(self, nodes):
|
||||
new_sess = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=new_sess,
|
||||
def set_in_maintenance(self, nodes):
|
||||
"""Set compute nodes in maintenance mode."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
self.auth_session = new_sess
|
||||
self.auth_session = auth_session
|
||||
for node in nodes:
|
||||
output = []
|
||||
host = nova.hosts.get(node)[0]
|
||||
@ -145,12 +159,13 @@ class OSClient:
|
||||
return output
|
||||
|
||||
def get_session(self):
|
||||
"""Get the authentication section."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
return auth_session
|
||||
|
||||
def get_node_status(self, node):
|
||||
"""
|
||||
Check the node nova-service status and if it's disabled or not
|
||||
"""Check the node nova-service status and if it's disabled or not.
|
||||
|
||||
:param node: dict contains node info
|
||||
:return: True or False. True => node disabled, False => node is enabled
|
||||
or unknow status !
|
||||
@ -172,6 +187,7 @@ class OSClient:
|
||||
return False
|
||||
|
||||
def disable_node(self, node):
|
||||
"""Disable nova on the failing node."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
@ -189,7 +205,7 @@ class OSClient:
|
||||
nova.services.disable_log_reason(
|
||||
host=node.get('host'),
|
||||
binary=node.get('binary'),
|
||||
reason='Host Failed and needs to be evacuated.'
|
||||
reason='Host failed and needs to be evacuated.'
|
||||
)
|
||||
del nova
|
||||
LOG.info('Compute host: %s has been disabled to be evacuated. '
|
||||
@ -200,6 +216,7 @@ class OSClient:
|
||||
return True
|
||||
|
||||
def get_hypervisor_instances(self, node):
|
||||
"""Get instances from an hypervisor."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
@ -209,8 +226,8 @@ class OSClient:
|
||||
return hypervisors[0].servers
|
||||
|
||||
def get_hypervisor(self, node):
|
||||
"""
|
||||
Get an instance of the hypervisor, so you can do any operation you want.
|
||||
"""Get an instance of the hypervisor.
|
||||
|
||||
:param node: dict contains host index
|
||||
:return: Hypervisor
|
||||
"""
|
||||
@ -223,6 +240,7 @@ class OSClient:
|
||||
return hypervisors[0]
|
||||
|
||||
def get_instances_list(self, node):
|
||||
"""Get instances running on a node for all tenants."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
@ -239,6 +257,7 @@ class OSClient:
|
||||
return self.get_instances_list(node)
|
||||
|
||||
def list_tenants(self):
|
||||
"""List tenants."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
keystone = keystoneclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
@ -251,6 +270,7 @@ class OSClient:
|
||||
return projects_data
|
||||
|
||||
def users_on_tenant(self, tenant):
|
||||
"""List user per project."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
keystone = keystoneclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type,
|
||||
@ -259,7 +279,7 @@ class OSClient:
|
||||
try:
|
||||
users = keystone.users.list(default_project=tenant)
|
||||
except Exception as e:
|
||||
print e
|
||||
print(e)
|
||||
users_list = []
|
||||
for user in users:
|
||||
users_list.append(user.to_dict())
|
||||
@ -267,6 +287,7 @@ class OSClient:
|
||||
return users_list
|
||||
|
||||
def get_hypervisors_stats(self):
|
||||
"""Get stats for all hypervisors."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
@ -274,6 +295,7 @@ class OSClient:
|
||||
return stats.to_dict()
|
||||
|
||||
def get_hypervisor_details(self, node):
|
||||
"""Get details about hypervisor running on the provided node."""
|
||||
auth_session = session.Session(auth=self.auth_session.auth)
|
||||
nova = novaclient.Client(session=auth_session,
|
||||
endpoint_type=self.endpoint_type)
|
||||
|
@ -1,4 +1,5 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
"""Utility functions shared from all modules into the project."""
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -11,18 +12,22 @@
|
||||
# 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 os
|
||||
from osha.common.osclient import OSClient
|
||||
|
||||
import jinja2
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
import jinja2
|
||||
|
||||
from osha.common.osclient import OSClient
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def env(*env_vars, **kwargs):
|
||||
"""Get all environment variables."""
|
||||
for variable in env_vars:
|
||||
value = os.environ.get(variable, None)
|
||||
if value:
|
||||
@ -31,7 +36,8 @@ def env(*env_vars, **kwargs):
|
||||
|
||||
|
||||
def get_os_client():
|
||||
"""
|
||||
"""Return the OpenStack client.
|
||||
|
||||
Loads credentials from [keystone_authtoken] section in the configuration
|
||||
file and initialize the client and return an instance of the client
|
||||
:return: Initialized instance of OS Client
|
||||
@ -53,14 +59,15 @@ def get_os_client():
|
||||
|
||||
|
||||
def load_jinja_templates(template_dir, template_name, template_vars):
|
||||
"""
|
||||
Load and render existing Jinja2 templates. The main purpose of the function
|
||||
is to prepare the message to be sent and render it for the driver to send
|
||||
it directly
|
||||
"""Load and render existing Jinja2 templates.
|
||||
|
||||
The main purpose of the function is to prepare the message to be sent and
|
||||
render it for the driver to send it directly.
|
||||
|
||||
:param template_dir: Location where jinja2 templates are stored
|
||||
:param template_name: name of the template to load it
|
||||
:param template_vars: Dict to replace existing vars in the template with
|
||||
values.
|
||||
values.
|
||||
:return: String message
|
||||
"""
|
||||
template_loader = jinja2.FileSystemLoader(searchpath=template_dir)
|
||||
@ -70,7 +77,8 @@ def load_jinja_templates(template_dir, template_name, template_vars):
|
||||
|
||||
|
||||
def get_admin_os_client():
|
||||
"""
|
||||
"""Return admin client data.
|
||||
|
||||
Loads credentials from [keystone_authtoken] section in the configuration
|
||||
file and initialize the client with admin privileges and return
|
||||
an instance of the client
|
||||
|
@ -1,4 +1,4 @@
|
||||
# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
||||
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -12,52 +12,58 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Abstract fencer"""
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class FencerBaseDriver(object):
|
||||
"""
|
||||
Abstract class that all fencer plugins should implement to have a
|
||||
unified interface and as many plugins as we want...
|
||||
|
||||
"""Abstract class that all fencer plugins.
|
||||
|
||||
Should be implemented to have a unified interface and as many plugins as
|
||||
needed.
|
||||
"""
|
||||
|
||||
def __init__(self, node, **kwargs):
|
||||
"""
|
||||
Initializing the driver. Any fencer driver requires the following
|
||||
parameters to do the api calls. All these parameters can be passed from
|
||||
the configuration file in /etc/osha/osha.conf (default)
|
||||
"""Initialize the driver.
|
||||
|
||||
Any fencer driver requires the following parameters to do the api
|
||||
calls. All these parameters can be passed from the configuration
|
||||
file in /etc/osha/osha.conf (default).
|
||||
|
||||
:param node: dict with all node details. (/etc/osha/servers.yml) ?
|
||||
:param kwargs: any additional parameters can be passed using this config
|
||||
option.
|
||||
:param kwargs: any additional parameters can be passed using this
|
||||
config option.
|
||||
"""
|
||||
self.node = node
|
||||
self.kwargs = kwargs
|
||||
|
||||
@abc.abstractmethod
|
||||
def graceful_shutdown(self):
|
||||
"""
|
||||
Gracefully shutdown the compute node to evacuate it.
|
||||
"""
|
||||
"""Gracefully shutdown the compute node to evacuate it."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def force_shutdown(self):
|
||||
"""
|
||||
Force shutdown the compute node to evacuate it. May be you can try force
|
||||
shutdown if the graceful shutdown failed
|
||||
"""Force shutdown the compute node to evacuate it.
|
||||
|
||||
May be you can try force shutdown if the graceful shutdown failed.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def status(self):
|
||||
"""
|
||||
Get compute node status. should return 1 if on and 0 if off or
|
||||
-1 if error or unknown power status
|
||||
"""Get compute node status.
|
||||
|
||||
Should return 1 if on and 0 if off or -1 if error or unknown power
|
||||
status.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_info(self):
|
||||
"""
|
||||
Get Driver information ..
|
||||
"""Get Driver information.
|
||||
|
||||
:return: dict of name, version, author, ...
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user