Add an interactive CLI for browsing and rebuilding appliance VMs
(cherry picked from commit 7d8e569999907209e114a10064f97ad528c0b668)
This commit is contained in:
parent
cb8a781c86
commit
272a42ada8
@ -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
129
akanda/rug/cli/browse.py
Normal 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
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user