Add an interactive CLI for browsing and rebuilding appliance VMs

(cherry picked from commit 7d8e569999907209e114a10064f97ad528c0b668)
This commit is contained in:
Ryan Petrello 2014-07-08 09:04:53 -07:00 committed by Ryan Petrello
parent cb8a781c86
commit 272a42ada8
5 changed files with 137 additions and 2 deletions

View File

@ -66,13 +66,14 @@ class MissingIPAllocation(Exception):
class Router(object):
def __init__(self, id_, tenant_id, name, admin_state_up,
def __init__(self, id_, tenant_id, name, admin_state_up, status,
external_port=None, internal_ports=None,
management_port=None, floating_ips=None):
self.id = id_
self.tenant_id = tenant_id
self.name = name
self.admin_state_up = admin_state_up
self.status = status
self.external_port = external_port
self.management_port = management_port
self.internal_ports = internal_ports or []
@ -111,6 +112,7 @@ class Router(object):
d['tenant_id'],
d['name'],
d['admin_state_up'],
d['status'],
external_port,
internal_ports,
management_port,

129
akanda/rug/cli/browse.py Normal file
View File

@ -0,0 +1,129 @@
# Copyright 2014 DreamHost, LLC
#
# Author: DreamHost, LLC
#
# 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.
"""Interactive CLI for rebuilding routers
"""
import logging
from akanda.rug import commands
from akanda.rug.api import nova as nova_api
from akanda.rug.api import quantum as quantum_api
from akanda.rug.cli import message
from blessed import Terminal
from oslo.config import cfg
class BrowseRouters(message.MessageSending):
log = logging.getLogger(__name__)
def __init__(self, *a, **kw):
self.term = Terminal()
self.nova = nova_api.Nova(cfg.CONF)
self.quantum = quantum_api.Quantum(cfg.CONF)
self.position = 0
super(BrowseRouters, self).__init__(*a, **kw)
def take_action(self, parsed_args):
with self.term.fullscreen():
with self.term.cbreak():
val = None
while val != u'q':
if not val:
self.fetch_routers()
elif val.is_sequence:
if val.code == self.term.KEY_DOWN:
self.move_down()
if val.code == self.term.KEY_UP:
self.move_up()
elif val == u'j':
self.move_down()
elif val == u'k':
self.move_up()
elif val == u'r':
self.reload_router()
self.fetch_routers()
self.print_routers()
val = self.term.inkey(timeout=5)
def fetch_routers(self):
self.routers = self.quantum.get_routers()
for router in self.routers:
instance = self.nova.get_instance(router)
if instance and instance.image:
image = self.nova.client.images.get(instance.image['id'])
status = self.term.red('OUT-OF-DATE')
if image.id == cfg.CONF.router_image_uuid:
status = self.term.green('LATEST')
name = status.ljust(11) + ' ' + image.name
setattr(
router,
'image',
name
)
else:
setattr(router, 'image', '<no vm>')
def print_routers(self):
visible_height = self.term.height - 2
offset = 0
if len(self.routers) > visible_height:
offset = self.position
offset = min(offset, len(self.routers) - visible_height - 1)
routers = self.routers[offset:]
with self.term.location():
for i, r in enumerate(routers):
if i > visible_height:
continue
formatter = lambda x: x
args = [
r.id,
r.name,
self.router_states[r.status](r.status.ljust(6)),
r.image
]
if i + offset == self.position:
formatter = self.term.reverse
print self.term.move(i, 0) + formatter(' '.join(args)).ljust(
self.term.width
)
def make_message(self, router):
return {
'command': commands.ROUTER_UPDATE,
'router_id': router.id,
'tenant_id': router.tenant_id
}
def reload_router(self):
router = self.routers[self.position]
self.send_message(self.make_message(router))
def move_up(self):
self.position = max(0, self.position-1)
def move_down(self):
self.position = min(len(self.routers)-1, self.position+1)
@property
def router_states(self):
return {
'ACTIVE': self.term.green,
'BUILD': self.term.yellow,
'DOWN': self.term.red,
'ERROR': self.term.red
}

View File

@ -43,7 +43,9 @@ class MessageSending(command.Command):
self.app.rug_ini.amqp_url,
self.app.rug_ini.outgoing_notifications_exchange,
)
payload = self.make_message(parsed_args)
self.send_message(self.make_message(parsed_args))
def send_message(self, payload):
msg = {
'event_type': 'akanda.rug.command',
'payload': payload,

View File

@ -6,3 +6,4 @@ kombu>=2.4.8
WebOb>=1.2.3,<1.3
python-novaclient>=2.15.0
cliff>=1.4.3
blessed>=1.9.1

View File

@ -43,6 +43,7 @@ akanda.rug.cli =
tenant debug=akanda.rug.cli.tenant:TenantDebug
tenant manage=akanda.rug.cli.tenant:TenantManage
workers debug=akanda.rug.cli.worker:WorkerDebug
interactive=akanda.rug.cli.rebuild:RebuildRouters
poll=akanda.rug.cli.poll:Poll
[build_sphinx]