summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/adminclient.py63
-rw-r--r--nova/api/ec2/admin.py111
2 files changed, 152 insertions, 22 deletions
diff --git a/nova/adminclient.py b/nova/adminclient.py
index c614b274c..fe2aca351 100644
--- a/nova/adminclient.py
+++ b/nova/adminclient.py
@@ -23,6 +23,8 @@ import base64
import boto
import boto.exception
import httplib
+import re
+import string
from boto.ec2.regioninfo import RegionInfo
@@ -165,19 +167,20 @@ class HostInfo(object):
**Fields Include**
- * Disk stats
- * Running Instances
- * Memory stats
- * CPU stats
- * Network address info
- * Firewall info
- * Bridge and devices
-
+ * Hostname
+ * Compute service status
+ * Volume service status
+ * Instance count
+ * Volume count
"""
def __init__(self, connection=None):
self.connection = connection
self.hostname = None
+ self.compute = None
+ self.volume = None
+ self.instance_count = 0
+ self.volume_count = 0
def __repr__(self):
return 'Host:%s' % self.hostname
@@ -188,7 +191,39 @@ class HostInfo(object):
# this is needed by the sax parser, so ignore the ugly name
def endElement(self, name, value, connection):
- setattr(self, name, value)
+ fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
+ setattr(self, fixed_name, value)
+
+
+class Vpn(object):
+ """
+ Information about a Vpn, as parsed through SAX
+
+ **Fields Include**
+
+ * instance_id
+ * project_id
+ * public_ip
+ * public_port
+ * created_at
+ * internal_ip
+ * state
+ """
+
+ def __init__(self, connection=None):
+ self.connection = connection
+ self.instance_id = None
+ self.project_id = None
+
+ def __repr__(self):
+ return 'Vpn:%s:%s' % (self.project_id, self.instance_id)
+
+ def startElement(self, name, attrs, connection):
+ return None
+
+ def endElement(self, name, value, connection):
+ fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
+ setattr(self, fixed_name, value)
class InstanceType(object):
@@ -422,6 +457,16 @@ class NovaAdminClient(object):
zip = self.apiconn.get_object('GenerateX509ForUser', params, UserInfo)
return zip.file
+ def start_vpn(self, project):
+ """
+ Starts the vpn for a user
+ """
+ return self.apiconn.get_object('StartVpn', {'Project': project}, Vpn)
+
+ def get_vpns(self):
+ """Return a list of vpn with project name"""
+ return self.apiconn.get_list('DescribeVpns', {}, [('item', Vpn)])
+
def get_hosts(self):
return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)])
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index 735951082..e2a05fce1 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -21,14 +21,18 @@ Admin API controller, exposed through http via the api worker.
"""
import base64
+import datetime
from nova import db
from nova import exception
+from nova import flags
from nova import log as logging
+from nova import utils
from nova.auth import manager
from nova.compute import instance_types
+FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.api.ec2.admin')
@@ -55,12 +59,25 @@ def project_dict(project):
return {}
-def host_dict(host):
+def host_dict(host, compute_service, instances, volume_service, volumes, now):
"""Convert a host model object to a result dict"""
- if host:
- return host.state
- else:
- return {}
+ rv = {'hostanme': host, 'instance_count': len(instances),
+ 'volume_count': len(volumes)}
+ if compute_service:
+ latest = compute_service['updated_at'] or compute_service['created_at']
+ delta = now - latest
+ if delta.seconds <= FLAGS.service_down_time:
+ rv['compute'] = 'up'
+ else:
+ rv['compute'] = 'down'
+ if volume_service:
+ latest = volume_service['updated_at'] or volume_service['created_at']
+ delta = now - latest
+ if delta.seconds <= FLAGS.service_down_time:
+ rv['volume'] = 'up'
+ else:
+ rv['volume'] = 'down'
+ return rv
def instance_dict(name, inst):
@@ -71,6 +88,25 @@ def instance_dict(name, inst):
'flavor_id': inst['flavorid']}
+def vpn_dict(project, vpn_instance):
+ rv = {'project_id': project.id,
+ 'public_ip': project.vpn_ip,
+ 'public_port': project.vpn_port}
+ if vpn_instance:
+ rv['instance_id'] = vpn_instance['ec2_id']
+ rv['created_at'] = utils.isotime(vpn_instance['created_at'])
+ address = vpn_instance.get('fixed_ip', None)
+ if address:
+ rv['internal_ip'] = address['address']
+ if utils.vpn_ping(project.vpn_ip, project.vpn_port):
+ rv['state'] = 'running'
+ else:
+ rv['state'] = 'down'
+ else:
+ rv['state'] = 'pending'
+ return rv
+
+
class AdminController(object):
"""
API Controller for users, hosts, nodes, and workers.
@@ -223,19 +259,68 @@ class AdminController(object):
raise exception.ApiError(_('operation must be add or remove'))
return True
+ def _vpn_for(self, context, project_id):
+ """Get the VPN instance for a project ID."""
+ for instance in db.instance_get_all_by_project(context, project_id):
+ if (instance['image_id'] == FLAGS.vpn_image_id
+ and not instance['state_description'] in
+ ['shutting_down', 'shutdown']):
+ return instance
+
+ def start_vpn(self, context, project):
+ instance = self._vpn_for(context, project)
+ if not instance:
+ # NOTE(vish) import delayed because of __init__.py
+ from nova.cloudpipe import pipelib
+ pipe = pipelib.CloudPipe()
+ try:
+ pipe.launch_vpn_instance(project)
+ except db.NoMoreNetworks:
+ raise exception.ApiError("Unable to claim IP for VPN instance"
+ ", ensure it isn't running, and try "
+ "again in a few minutes")
+ instance = self._vpn_for(context, project)
+ return {'instance_id': instance['ec2_id']}
+
+ def describe_vpns(self, context):
+ vpns = []
+ for project in manager.AuthManager().get_projects():
+ instance = self._vpn_for(context, project.id)
+ vpns.append(vpn_dict(project, instance))
+ return {'items': vpns}
+
# FIXME(vish): these host commands don't work yet, perhaps some of the
# required data can be retrieved from service objects?
- def describe_hosts(self, _context, **_kwargs):
+ def describe_hosts(self, context, **_kwargs):
"""Returns status info for all nodes. Includes:
- * Disk Space
- * Instance List
- * RAM used
- * CPU used
- * DHCP servers running
- * Iptables / bridges
+ * Hostname
+ * Compute (up, down, None)
+ * Instance count
+ * Volume (up, down, None)
+ * Volume Count
"""
- return {'hostSet': [host_dict(h) for h in db.host_get_all()]}
+ services = db.service_get_all(context)
+ now = datetime.datetime.utcnow()
+ hosts = []
+ rv = []
+ for host in [service['host'] for service in services]:
+ if not host in hosts:
+ hosts.append(host)
+ for host in hosts:
+ compute = [s for s in services if s['host'] == host \
+ and s['binary'] == 'nova-compute']
+ if compute:
+ compute = compute[0]
+ instances = db.instance_get_all_by_host(context, host)
+ volume = [s for s in services if s['host'] == host \
+ and s['binary'] == 'nova-volume']
+ if volume:
+ volume = volume[0]
+ volumes = db.volume_get_all_by_host(context, host)
+ rv.append(host_dict(host, compute, instances, volume, volumes,
+ now))
+ return {'hosts': rv}
def describe_host(self, _context, name, **_kwargs):
"""Returns status info for single node."""