[MGM] Migrate to oslo.config

Major configuration change. See examples in etc/ directory.

Change-Id: Iea3d9fd4b313d6325b644a44d8841fd011f2197e
This commit is contained in:
David Shrewsbury
2013-10-14 14:55:21 +00:00
parent 7244dc5049
commit 3d36a4248e
10 changed files with 227 additions and 231 deletions

71
etc/mgm.cfg Normal file
View File

@@ -0,0 +1,71 @@
########################################################################
# A sample configuration file read by the Libra pool manager utility.
########################################################################
#-----------------------------------------------------------------------
# The [DEFAULT] section contains options common to the various Libra
# utilities (worker, mgm, etc).
#-----------------------------------------------------------------------
[DEFAULT]
# Options to enable more verbose output
#verbose = false
#debug = false
# Daemon process options
#daemon = true
#user = libra
#group = libra
# Other logging options
#syslog = false
#syslog_socket = /dev/log
#syslog_faciltiy = local7
#logstash = HOST:PORT
#-----------------------------------------------------------------------
# Options for utilities that are Gearman workers or clients.
#-----------------------------------------------------------------------
[gearman]
#servers = localhost:4730, HOST:PORT
#keepalive = false
#keepcnt = COUNT
#keepidle = SECONDS
#keepintvl = SECONDS
#poll = 1
#reconnect_sleep = 60
#ssl_ca = /path/to/ssl_ca
#ssl_cert = /path/to/ssl_cert
#ssl_key = /path/to/ssl_key
#-----------------------------------------------------------------------
# The [mgm] section is specific to the libra_mgm utility.
#-----------------------------------------------------------------------
[mgm]
# Options with defaults
#pid = /var/run/libra/libra_mgm.pid
#logfile = /var/log/libra/libra_mgm.log
#threads = 4
#rm_fip_ignore_500 = false
#nova_insecure = false
# Required options
az = 1
nova_auth_url = https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/
nova_keyname = default
nova_region = region
nova_secgroup = default
nova_user = username
nova_pass = password
nova_image = 12345
nova_image_size = standard.medium
# Others
node_basename = BASENAME
nova_az_name = NAME
nova_bypass_url = URL
nova_net_id = ID
nova_tenant = TENANT
nova_tenant_id = TENANTID

View File

@@ -11,3 +11,80 @@
# 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
mgm_group = cfg.OptGroup('mgm', 'Libra Pool Manager options')
cfg.CONF.register_group(mgm_group)
cfg.CONF.register_opts(
[
cfg.IntOpt('az',
required=True,
help='The az the nodes and IPs will reside in (to be '
'passed to the API server'),
cfg.StrOpt('logfile',
default='/var/log/libra/libra_mgm.log',
help='Log file'),
cfg.StrOpt('pid',
default='/var/run/libra/libra_mgm.pid',
help='PID file'),
cfg.StrOpt('node_basename',
help='prepend the name of all nodes with this'),
cfg.StrOpt('nova_auth_url',
required=True,
help='the auth URL for the Nova API'),
cfg.StrOpt('nova_user',
required=True,
help='the username for the Nova API'),
cfg.StrOpt('nova_pass',
required=True,
help='the password for the Nova API'),
cfg.StrOpt('nova_region',
required=True,
help='the region to use for the Nova API'),
cfg.StrOpt('nova_tenant',
help='the tenant name for the Nova API'),
cfg.StrOpt('nova_tenant_id',
help='the tenant ID for the Nova API'),
cfg.StrOpt('nova_keyname',
required=True,
help='the key name for new nodes spun up in the Nova API'),
cfg.StrOpt('nova_secgroup',
required=True,
help='the security group for new nodes spun up in the '
'Nova API'),
cfg.StrOpt('nova_image',
required=True,
help='the image ID or name to use for new nodes spun up '
'in the Nova API'),
cfg.StrOpt('nova_image_size',
required=True,
help='the image size ID (flavor ID) or name to use for '
'new nodes spun up in the Nova API'),
cfg.StrOpt('nova_az_name',
help='the az name to build in'),
cfg.BoolOpt('nova_insecure',
default=False,
help='do not attempt to verify Nova/Keystone SSL '
'certificates'),
cfg.StrOpt('nova_bypass_url',
help='use a different URL to the one supplied by the '
'service'),
cfg.StrOpt('nova_net_id',
help='The ID of the network to put loadbalancer on '
'(Required if multiple Neutron networks)'),
cfg.BoolOpt('rm_fip_ignore_500',
default=False,
help='Ignore HTTP 500 error when removing a floating IP'),
cfg.IntOpt('tcp_check_port',
help='Port number to ping to check floating IP assign '
'worked'),
cfg.IntOpt('threads',
default=4,
help='Number of worker threads to spawn'),
],
group=mgm_group
)

View File

@@ -14,6 +14,8 @@
from time import sleep
from novaclient import exceptions
from oslo.config import cfg
from libra.mgm.nova import Node, BuildError, NotFound
@@ -23,14 +25,13 @@ class BuildController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, msg):
def __init__(self, logger, msg):
self.logger = logger
self.msg = msg
self.args = args
def run(self):
try:
nova = Node(self.args)
nova = Node()
except Exception:
self.logger.exception("Error initialising Nova connection")
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE
@@ -102,9 +103,10 @@ class BuildController(object):
break
self.msg['addr'] = address['addr']
self.msg['type'] = "basename: {0}, image: {1}".format(
self.args.node_basename, self.args.nova_image
cfg.CONF['mgm']['node_basename'],
cfg.CONF['mgm']['nova_image']
)
self.msg['az'] = self.args.az
self.msg['az'] = cfg.CONF['mgm']['az']
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_SUCCESS
self.logger.info('Node {0} returned'.format(status['name']))
return self.msg

View File

@@ -21,14 +21,13 @@ class DeleteController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, msg):
def __init__(self, logger, msg):
self.logger = logger
self.msg = msg
self.args = args
def run(self):
try:
nova = Node(self.args)
nova = Node()
except Exception:
self.logger.exception("Error initialising Nova connection")
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE

View File

@@ -25,10 +25,9 @@ class PoolMgmController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, json_msg):
def __init__(self, logger, json_msg):
self.logger = logger
self.msg = json_msg
self.args = args
def run(self):
if self.ACTION_FIELD not in self.msg:
@@ -40,21 +39,15 @@ class PoolMgmController(object):
try:
if action == 'BUILD_DEVICE':
controller = BuildController(self.logger, self.args, self.msg)
controller = BuildController(self.logger, self.msg)
elif action == 'DELETE_DEVICE':
controller = DeleteController(self.logger, self.args, self.msg)
controller = DeleteController(self.logger, self.msg)
elif action == 'BUILD_IP':
controller = BuildIpController(
self.logger, self.args, self.msg
)
controller = BuildIpController(self.logger, self.msg)
elif action == 'ASSIGN_IP':
controller = AssignIpController(
self.logger, self.args, self.msg
)
controller = AssignIpController(self.logger, self.msg)
elif action == 'REMOVE_IP':
controller = RemoveIpController(
self.logger, self.args, self.msg
)
controller = RemoveIpController(self.logger, self.msg)
else:
self.logger.error(
"Invalid `{0}` value: {1}".format(

View File

@@ -15,6 +15,8 @@
import socket
import time
from novaclient import exceptions
from oslo.config import cfg
from libra.mgm.nova import Node
@@ -24,14 +26,13 @@ class BuildIpController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, msg):
def __init__(self, logger, msg):
self.logger = logger
self.msg = msg
self.args = args
def run(self):
try:
nova = Node(self.args)
nova = Node()
except Exception:
self.logger.exception("Error initialising Nova connection")
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE
@@ -59,14 +60,13 @@ class AssignIpController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, msg):
def __init__(self, logger, msg):
self.logger = logger
self.msg = msg
self.args = args
def run(self):
try:
nova = Node(self.args)
nova = Node()
except Exception:
self.logger.exception("Error initialising Nova connection")
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE
@@ -79,8 +79,9 @@ class AssignIpController(object):
try:
node_id = nova.get_node(self.msg['name'])
nova.vip_assign(node_id, self.msg['ip'])
if self.args.tcp_check_port:
self.check_ip(self.msg['ip'], self.args.tcp_check_port)
if cfg.CONF['mgm']['tcp_check_port']:
self.check_ip(self.msg['ip'],
cfg.CONF['mgm']['tcp_check_port'])
except:
self.logger.exception(
'Error assigning Floating IP {0} to {1}'
@@ -118,14 +119,13 @@ class RemoveIpController(object):
RESPONSE_SUCCESS = 'PASS'
RESPONSE_FAILURE = 'FAIL'
def __init__(self, logger, args, msg):
def __init__(self, logger, msg):
self.logger = logger
self.msg = msg
self.args = args
def run(self):
try:
nova = Node(self.args)
nova = Node()
except Exception:
self.logger.exception("Error initialising Nova connection")
self.msg[self.RESPONSE_FIELD] = self.RESPONSE_FAILURE

View File

@@ -17,6 +17,8 @@ import json
import socket
import time
from oslo.config import cfg
from libra.common.json_gearman import JSONGearmanWorker
from libra.mgm.controllers.root import PoolMgmController
@@ -24,45 +26,44 @@ from libra.mgm.controllers.root import PoolMgmController
def handler(worker, job):
logger = worker.logger
logger.debug("Received JSON message: {0}".format(json.dumps(job.data)))
controller = PoolMgmController(logger, worker.args, job.data)
controller = PoolMgmController(logger, job.data)
response = controller.run()
logger.debug("Return JSON message: {0}".format(json.dumps(response)))
return response
def worker_thread(logger, args):
def worker_thread(logger):
logger.info("Registering task libra_pool_mgm")
hostname = socket.gethostname()
server_list = []
for host_port in args.gearman:
for host_port in cfg.CONF['gearman']['servers']:
host, port = host_port.split(':')
server_list.append({'host': host,
'port': int(port),
'keyfile': args.gearman_ssl_key,
'certfile': args.gearman_ssl_cert,
'ca_certs': args.gearman_ssl_ca,
'keepalive': args.gearman_keepalive,
'keepcnt': args.gearman_keepcnt,
'keepidle': args.gearman_keepidle,
'keepintvl': args.gearman_keepintvl})
'keyfile': cfg.CONF['gearman']['ssl_key'],
'certfile': cfg.CONF['gearman']['ssl_cert'],
'ca_certs': cfg.CONF['gearman']['ssl_ca'],
'keepalive': cfg.CONF['gearman']['keepalive'],
'keepcnt': cfg.CONF['gearman']['keepcnt'],
'keepidle': cfg.CONF['gearman']['keepidle'],
'keepintvl': cfg.CONF['gearman']['keepintvl']})
worker = JSONGearmanWorker(server_list)
worker.set_client_id(hostname)
worker.register_task('libra_pool_mgm', handler)
worker.logger = logger
worker.args = args
retry = True
while (retry):
try:
worker.work(args.gearman_poll)
worker.work(cfg.CONF['gearman']['poll'])
except KeyboardInterrupt:
retry = False
except gearman.errors.ServerUnavailable:
logger.error("Job server(s) went away. Reconnecting.")
time.sleep(args.reconnect_sleep)
time.sleep(cfg.CONF['gearman']['reconnect_sleep'])
retry = True
except Exception:
logger.exception("Exception in worker")

View File

@@ -17,30 +17,28 @@ import daemon.pidfile
import daemon.runner
import grp
import pwd
import sys
import os
import threading
from libra.common.options import Options, setup_logging
from libra import __version__
from libra.common.options import add_common_options, libra_logging, CONF
from libra.mgm.gearman_worker import worker_thread
class Server(object):
def __init__(self, args):
self.args = args
def __init__(self):
self.logger = None
def main(self):
self.logger = setup_logging('libra_mgm', self.args)
self.logger = libra_logging('libra_mgm', 'mgm')
self.logger.info(
'Libra Pool Manager worker started, spawning {0} threads'
.format(self.args.threads)
.format(CONF['mgm']['threads'])
)
thread_list = []
for x in xrange(0, self.args.threads):
for x in xrange(0, CONF['mgm']['threads']):
thd = threading.Thread(
target=worker_thread, args=[self.logger, self.args]
target=worker_thread, args=[self.logger]
)
thd.daemon = True
thread_list.append(thd)
@@ -50,163 +48,15 @@ class Server(object):
def main():
options = Options('mgm', 'Node Management Daemon')
options.parser.add_argument(
'--az', type=int,
help='The az the nodes and IPs will reside in (to be passed to the API'
' server)'
)
options.parser.add_argument(
'--node_basename', dest='node_basename',
help='prepend the name of all nodes with this'
)
options.parser.add_argument(
'--nova_auth_url',
help='the auth URL for the Nova API'
)
options.parser.add_argument(
'--nova_user',
help='the username for the Nova API'
)
options.parser.add_argument(
'--nova_pass',
help='the password for the Nova API'
)
options.parser.add_argument(
'--nova_region',
help='the region to use for the Nova API'
)
options.parser.add_argument(
'--nova_tenant',
help='the tenant name for the Nova API'
)
options.parser.add_argument(
'--nova_tenant_id',
help='the tenant ID for the Nova API'
)
options.parser.add_argument(
'--nova_keyname',
help='the key name for new nodes spun up in the Nova API'
)
options.parser.add_argument(
'--nova_secgroup',
help='the security group for new nodes spun up in the Nova API'
)
options.parser.add_argument(
'--nova_image',
help='the image ID or name to use for new nodes spun up in the'
' Nova API'
)
options.parser.add_argument(
'--nova_image_size',
help='the image size ID (flavor ID) or name to use for new nodes spun'
' up in the Nova API'
)
options.parser.add_argument(
'--nova_az_name',
help='the az name to build in'
)
options.parser.add_argument(
'--nova_insecure', action='store_true',
help='do not attempt to verify Nova/Keystone SSL certificates'
)
options.parser.add_argument(
'--nova_bypass_url',
help='use a different URL to the one supplied by the service'
)
options.parser.add_argument(
'--nova_net_id',
help="The ID of the network to put loadbalancer on"
"(Required if multiple Neutron networks)")
options.parser.add_argument(
'--gearman', action='append', metavar='HOST:PORT', default=[],
help='Gearman job servers'
)
options.parser.add_argument(
'--gearman_keepalive', action="store_true",
help='use KEEPALIVE to Gearman server'
)
options.parser.add_argument(
'--gearman_keepcnt', type=int, metavar='COUNT',
help='max keepalive probes to send before killing connection'
)
options.parser.add_argument(
'--gearman_keepidle', type=int, metavar='SECONDS',
help='seconds of idle time before sending keepalive probes'
)
options.parser.add_argument(
'--gearman_keepintvl', type=int, metavar='SECONDS',
help='seconds between TCP keepalive probes'
)
options.parser.add_argument(
'--gearman_ssl_ca', metavar='FILE',
help='Gearman SSL certificate authority'
)
options.parser.add_argument(
'--gearman_ssl_cert', metavar='FILE',
help='Gearman SSL certificate'
)
options.parser.add_argument(
'--gearman_ssl_key', metavar='FILE',
help='Gearman SSL key'
)
options.parser.add_argument(
'--gearman_poll', type=int, metavar='TIME',
default=1, help='Gearman worker polling timeout'
)
options.parser.add_argument(
'--threads',
dest='threads', type=int, default=4,
help='Number of worker threads to spawn'
)
options.parser.add_argument(
'--tcp_check_port', type=int,
help='Port number to ping to check floating IP assign worked'
)
options.parser.add_argument(
'--rm_fip_ignore_500', action='store_true',
help='Ignore HTTP 500 error when removing a floating IP'
)
add_common_options()
CONF(project='libra', version=__version__)
args = options.run()
server = Server()
required_args = [
'az',
'nova_image', 'nova_image_size', 'nova_secgroup', 'nova_keyname',
'nova_region', 'nova_user', 'nova_pass', 'nova_auth_url'
]
# NOTE(LinuxJedi): We are checking for required args here because the
# parser can't yet check both command line and config file to see if an
# option has been set
missing_args = 0
for req in required_args:
test_var = getattr(args, req)
if test_var is None:
missing_args += 1
sys.stderr.write(
'{app}: error: argument --{test_var} is required\n'
.format(app=os.path.basename(sys.argv[0]), test_var=req))
if missing_args:
return 2
if not args.gearman:
# NOTE(shrews): Can't set a default in argparse method because the
# value is appended to the specified default.
args.gearman.append('localhost:4730')
elif not isinstance(args.gearman, list):
# NOTE(shrews): The Options object cannot intelligently handle
# creating a list from an option that may have multiple values.
# We convert it to the expected type here.
svr_list = args.gearman.split()
args.gearman = svr_list
server = Server(args)
if args.nodaemon:
if not CONF['daemon']:
server.main()
else:
pidfile = daemon.pidfile.TimeoutPIDLockFile(args.pid, 10)
pidfile = daemon.pidfile.TimeoutPIDLockFile(CONF['mgm']['pid'], 10)
if daemon.runner.is_pidfile_stale(pidfile):
pidfile.break_lock()
context = daemon.DaemonContext(
@@ -214,10 +64,10 @@ def main():
umask=0o022,
pidfile=pidfile
)
if args.user:
context.uid = pwd.getpwnam(args.user).pw_uid
if args.group:
context.gid = grp.getgrnam(args.group).gr_gid
if CONF['user']:
context.uid = pwd.getpwnam(CONF['user']).pw_uid
if CONF['group']:
context.gid = grp.getgrnam(CONF['group']).gr_gid
context.open()
server.main()

View File

@@ -16,6 +16,8 @@ import uuid
import sys
import urllib
from oslo.config import cfg
from novaclient import client
from novaclient import exceptions
@@ -35,36 +37,37 @@ class BuildError(Exception):
class Node(object):
def __init__(self, args):
def __init__(self):
self.nova = client.HTTPClient(
args.nova_user,
args.nova_pass,
args.nova_tenant,
args.nova_auth_url,
region_name=args.nova_region,
cfg.CONF['mgm']['nova_user'],
cfg.CONF['mgm']['nova_pass'],
cfg.CONF['mgm']['nova_tenant'],
cfg.CONF['mgm']['nova_auth_url'],
region_name=cfg.CONF['mgm']['nova_region'],
no_cache=True,
insecure=args.nova_insecure,
tenant_id=args.nova_tenant_id,
bypass_url=args.nova_bypass_url,
insecure=cfg.CONF['mgm']['nova_insecure'],
tenant_id=cfg.CONF['mgm']['nova_tenant_id'],
bypass_url=cfg.CONF['mgm']['nova_bypass_url'],
service_type='compute'
)
self.keyname = args.nova_keyname
self.secgroup = args.nova_secgroup
self.node_basename = args.node_basename
self.az = args.nova_az_name
self.net_id = args.nova_net_id
self.rm_fip_ignore_500 = args.rm_fip_ignore_500
self.keyname = cfg.CONF['mgm']['nova_keyname']
self.secgroup = cfg.CONF['mgm']['nova_secgroup']
self.node_basename = cfg.CONF['mgm']['node_basename']
self.az = cfg.CONF['mgm']['nova_az_name']
self.net_id = cfg.CONF['mgm']['nova_net_id']
self.rm_fip_ignore_500 = cfg.CONF['mgm']['rm_fip_ignore_500']
# Replace '_' with '-' in basename
if self.node_basename:
self.node_basename = self.node_basename.replace('_', '-')
self.image = args.nova_image
self.image = cfg.CONF['mgm']['nova_image']
if args.nova_image_size.isdigit():
self.node_type = args.nova_image_size
image_size = cfg.CONF['mgm']['nova_image_size']
if image_size.isdigit():
self.node_type = image_size
else:
self.node_type = self._get_flavor(args.nova_image_size)
self.node_type = self._get_flavor(image_size)
def build(self):
""" create a node, test it is running """

View File

@@ -2,7 +2,7 @@ pbr>=0.5.21,<1.0
eventlet
gearman>=2.0.2
oslo.config
oslo.config>=1.2.0
python-daemon>=1.6
python-logstash
python_novaclient>=2.14.1,<2.14.2