~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to bin/nova-manage

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Adam Gandelman
  • Date: 2013-02-22 09:27:29 UTC
  • mfrom: (1.1.68)
  • Revision ID: package-import@ubuntu.com-20130222092729-nn3gt8rf97uvts77
Tags: 2013.1.g3-0ubuntu1
[ Chuck Short ]
* New usptream release. 
* debian/patches/debian/patches/fix-ubuntu-tests.patch: Refreshed.
* debian/nova-baremetal.logrotate: Fix logfile path.
* debian/control, debian/nova-spiceproxy.{install, logrotate, upstart}:
  Add spice html5 proxy support.
* debian/nova-novncproxy.upstart: Start on runlevel [2345]
* debian/rules: Call testr directly since run_tests.sh -N gives weird return
  value when tests pass.
* debian/pyddist-overrides: Add websockify.
* debian/nova-common.postinst: Removed config file conversion, since
  the option is no longer available. (LP: #1110567)
* debian/control: Add python-pyasn1 as a dependency.
* debian/control: Add python-oslo-config as a dependency.
* debian/control: Suggest sysfsutils, sg3-utils, multipath-tools for fibre
  channel support.

[ Adam Gandelman ]
* debian/control: Fix typo (websocikfy -> websockify).

Show diffs side-by-side

added added

removed removed

Lines of Context:
59
59
import os
60
60
import sys
61
61
 
 
62
from oslo.config import cfg
 
63
 
62
64
# If ../nova/__init__.py exists, add ../ to Python search path, so that
63
65
# it will override what happens to be installed in /usr/(local/)lib/python...
64
66
POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
72
74
from nova.api.ec2 import ec2utils
73
75
from nova import availability_zones
74
76
from nova.compute import instance_types
75
 
from nova.compute import rpcapi as compute_rpcapi
76
77
from nova import config
77
78
from nova import context
78
79
from nova import db
79
80
from nova.db import migration
80
81
from nova import exception
81
 
from nova.openstack.common import cfg
82
82
from nova.openstack.common import cliutils
 
83
from nova.openstack.common.db.sqlalchemy import session as db_session
83
84
from nova.openstack.common import importutils
84
85
from nova.openstack.common import log as logging
85
86
from nova.openstack.common import rpc
86
87
from nova.openstack.common import timeutils
87
88
from nova import quota
88
89
from nova.scheduler import rpcapi as scheduler_rpcapi
 
90
from nova import servicegroup
89
91
from nova import utils
90
92
from nova import version
91
93
 
92
94
CONF = cfg.CONF
93
95
CONF.import_opt('network_manager', 'nova.service')
94
 
CONF.import_opt('service_down_time', 'nova.config')
 
96
CONF.import_opt('service_down_time', 'nova.service')
95
97
CONF.import_opt('flat_network_bridge', 'nova.network.manager')
96
98
CONF.import_opt('num_networks', 'nova.network.manager')
97
99
CONF.import_opt('multi_host', 'nova.network.manager')
98
100
CONF.import_opt('network_size', 'nova.network.manager')
99
101
CONF.import_opt('vlan_start', 'nova.network.manager')
100
102
CONF.import_opt('vpn_start', 'nova.network.manager')
101
 
CONF.import_opt('default_floating_pool', 'nova.network.manager')
 
103
CONF.import_opt('default_floating_pool', 'nova.network.floating_ips')
102
104
CONF.import_opt('public_interface', 'nova.network.linux_net')
103
105
 
104
106
QUOTAS = quota.QUOTAS
205
207
 
206
208
    @args('--path', dest='path', metavar='<path>', help='Script path')
207
209
    def script(self, path):
208
 
        """Runs the script from the specifed path with flags set properly.
 
210
        """Runs the script from the specified path with flags set properly.
209
211
        arguments: path"""
210
212
        exec(compile(open(path).read(), path, 'exec'), locals(), globals())
211
213
 
226
228
    @args('--key', dest="key", metavar='<key>', help='Key')
227
229
    @args('--value', dest="value", metavar='<value>', help='Value')
228
230
    def quota(self, project_id, key=None, value=None):
229
 
        """Set or display quotas for project"""
 
231
        """Set or display quotas for project."""
230
232
        ctxt = context.get_admin_context()
231
233
        project_quota = QUOTAS.get_project_quotas(ctxt, project_id)
232
234
        if key and key in project_quota:
250
252
    @args('--project', dest="project_id", metavar='<Project name>',
251
253
            help='Project name')
252
254
    def scrub(self, project_id):
253
 
        """Deletes data associated with project"""
 
255
        """Deletes data associated with project."""
254
256
        admin_context = context.get_admin_context()
255
257
        networks = db.project_get_networks(admin_context, project_id)
256
258
        for network in networks:
268
270
 
269
271
    @args('--host', dest="host", metavar='<host>', help='Host')
270
272
    def list(self, host=None):
271
 
        """Lists all fixed ips (optionally by host)"""
 
273
        """Lists all fixed ips (optionally by host)."""
272
274
        ctxt = context.get_admin_context()
273
275
 
274
276
        try:
307
309
        for fixed_ip in fixed_ips:
308
310
            hostname = None
309
311
            host = None
310
 
            mac_address = None
311
312
            network = all_networks.get(fixed_ip['network_id'])
312
313
            if network:
313
314
                has_ip = True
382
383
    @args('--interface', dest="interface", metavar='<interface>',
383
384
          help='Optional interface')
384
385
    def create(self, ip_range, pool=None, interface=None):
385
 
        """Creates floating ips for zone by range"""
 
386
        """Creates floating ips for zone by range."""
386
387
        admin_context = context.get_admin_context()
387
388
        if not pool:
388
389
            pool = CONF.default_floating_pool
402
403
 
403
404
    @args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
404
405
    def delete(self, ip_range):
405
 
        """Deletes floating ips by range"""
 
406
        """Deletes floating ips by range."""
406
407
        admin_context = context.get_admin_context()
407
408
 
408
409
        ips = ({'address': str(address)}
476
477
               gateway_v6=None, bridge=None, bridge_interface=None,
477
478
               dns1=None, dns2=None, project_id=None, priority=None,
478
479
               uuid=None, fixed_cidr=None):
479
 
        """Creates fixed ips for host by range"""
 
480
        """Creates fixed ips for host by range."""
480
481
        kwargs = dict(((k, v) for k, v in locals().iteritems()
481
482
                       if v and k != "self"))
482
483
        if multi_host is not None:
485
486
        net_manager.create_networks(context.get_admin_context(), **kwargs)
486
487
 
487
488
    def list(self):
488
 
        """List all created networks"""
 
489
        """List all created networks."""
489
490
        _fmt = "%-5s\t%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s"
490
491
        print _fmt % (_('id'),
491
492
                          _('IPv4'),
520
521
    @args('--uuid', dest='uuid', metavar='<uuid>',
521
522
            help='UUID of network to delete')
522
523
    def delete(self, fixed_range=None, uuid=None):
523
 
        """Deletes a network"""
 
524
        """Deletes a network."""
524
525
 
525
526
        if fixed_range is None and uuid is None:
526
527
            raise Exception(_("Please specify either fixed_range or uuid"))
560
561
        #1) Associate (set not None value given by project/host parameter)
561
562
        #2) Disassociate (set None by disassociate parameter)
562
563
        #3) Keep unchanged (project/host key is not added to 'net')
 
564
        if dis_project:
 
565
            net['project_id'] = None
 
566
        if dis_host:
 
567
            net['host'] = None
 
568
 
 
569
        # The --disassociate-X are boolean options, but if they user
 
570
        # mistakenly provides a value, it will be used as a positional argument
 
571
        # and be erroneously interepreted as some other parameter (e.g.
 
572
        # a project instead of host value). The safest thing to do is error-out
 
573
        # with a message indicating that there is probably a problem with
 
574
        # how the disassociate modifications are being used.
 
575
        if dis_project or dis_host:
 
576
            if project or host:
 
577
                error_msg = "ERROR: Unexpected arguments provided. Please " \
 
578
                    "use separate commands."
 
579
                print(error_msg)
 
580
                sys.exit(1)
 
581
            db.network_update(admin_context, network['id'], net)
 
582
            return
 
583
 
563
584
        if project:
564
585
            net['project_id'] = project
565
 
        elif dis_project:
566
 
            net['project_id'] = None
567
586
        if host:
568
587
            net['host'] = host
569
 
        elif dis_host:
570
 
            net['host'] = None
 
588
 
571
589
        db.network_update(admin_context, network['id'], net)
572
590
 
573
591
 
576
594
 
577
595
    @args('--host', dest="host", metavar='<host>', help='Host')
578
596
    def list(self, host=None):
579
 
        """Show a list of all instances"""
 
597
        """Show a list of all instances."""
580
598
 
581
599
        print ("%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s"
582
600
               "  %-10s %-10s %-10s %-5s" % (_('instance'),
615
633
 
616
634
 
617
635
class ServiceCommands(object):
618
 
    """Enable and disable running services"""
 
636
    """Enable and disable running services."""
619
637
 
620
638
    @args('--host', dest='host', metavar='<host>', help='Host')
621
639
    @args('--service', dest='service', metavar='<service>',
624
642
        """
625
643
        Show a list of all running services. Filter by host & service name.
626
644
        """
 
645
        servicegroup_api = servicegroup.API()
627
646
        ctxt = context.get_admin_context()
628
647
        now = timeutils.utcnow()
629
648
        services = db.service_get_all(ctxt)
630
 
        services = availability_zone.set_availability_zones(ctxt, services)
 
649
        services = availability_zones.set_availability_zones(ctxt, services)
631
650
        if host:
632
651
            services = [s for s in services if s['host'] == host]
633
652
        if service:
641
660
                    _('State'),
642
661
                    _('Updated_At'))
643
662
        for svc in services:
644
 
            delta = now - (svc['updated_at'] or svc['created_at'])
645
 
            alive = abs(utils.total_seconds(delta)) <= CONF.service_down_time
 
663
            alive = servicegroup_api.service_is_up(svc)
646
664
            art = (alive and ":-)") or "XXX"
647
665
            active = 'enabled'
648
666
            if svc['disabled']:
655
673
    @args('--service', dest='service', metavar='<service>',
656
674
            help='Nova service')
657
675
    def enable(self, host, service):
658
 
        """Enable scheduling for a service"""
 
676
        """Enable scheduling for a service."""
659
677
        ctxt = context.get_admin_context()
660
678
        svc = db.service_get_by_args(ctxt, host, service)
661
679
        if not svc:
667
685
    @args('--service', dest='service', metavar='<service>',
668
686
            help='Nova service')
669
687
    def disable(self, host, service):
670
 
        """Disable scheduling for a service"""
 
688
        """Disable scheduling for a service."""
671
689
        ctxt = context.get_admin_context()
672
690
        svc = db.service_get_by_args(ctxt, host, service)
673
691
        if not svc:
733
751
 
734
752
 
735
753
class HostCommands(object):
736
 
    """List hosts"""
 
754
    """List hosts."""
737
755
 
738
756
    def list(self, zone=None):
739
757
        """Show a list of all physical hosts. Filter by zone.
741
759
        print "%-25s\t%-15s" % (_('host'),
742
760
                                _('zone'))
743
761
        ctxt = context.get_admin_context()
744
 
        now = timeutils.utcnow()
745
762
        services = db.service_get_all(ctxt)
746
763
        services = availability_zones.set_availability_zones(ctxt, services)
747
764
        if zone:
771
788
        """Print the current database version."""
772
789
        print migration.db_version()
773
790
 
 
791
    @args('--max_rows', dest='max_rows', metavar='<number>',
 
792
            help='Maximum number of deleted rows to archive')
 
793
    def archive_deleted_rows(self, max_rows=None):
 
794
        """Move up to max_rows deleted rows from production tables to shadow
 
795
        tables.
 
796
        """
 
797
        if max_rows is not None:
 
798
            max_rows = int(max_rows)
 
799
        admin_context = context.get_admin_context()
 
800
        db.archive_deleted_rows(admin_context, max_rows)
 
801
 
774
802
 
775
803
class InstanceTypeCommands(object):
776
804
    """Class for managing instance types / flavors."""
777
805
 
778
806
    def _print_instance_types(self, name, val):
779
 
        deleted = ('', ', inactive')[val["deleted"] == 1]
780
807
        is_public = ('private', 'public')[val["is_public"] == 1]
781
808
        print ("%s: Memory: %sMB, VCPUS: %s, Root: %sGB, Ephemeral: %sGb, "
782
809
            "FlavorID: %s, Swap: %sMB, RXTX Factor: %s, %s, ExtraSpecs %s") % (
802
829
            help='Make flavor accessible to the public')
803
830
    def create(self, name, memory, vcpus, root_gb, ephemeral_gb=0,
804
831
               flavorid=None, swap=0, rxtx_factor=1.0, is_public=True):
805
 
        """Creates instance types / flavors"""
 
832
        """Creates instance types / flavors."""
806
833
        try:
807
834
            instance_types.create(name, memory, vcpus, root_gb,
808
835
                                  ephemeral_gb, flavorid, swap, rxtx_factor,
828
855
    @args('--name', dest='name', metavar='<name>',
829
856
            help='Name of instance type/flavor')
830
857
    def delete(self, name):
831
 
        """Marks instance types / flavors as deleted"""
 
858
        """Marks instance types / flavors as deleted."""
832
859
        try:
833
860
            instance_types.destroy(name)
834
861
        except exception.InstanceTypeNotFound:
835
862
            print _("Valid instance type name is required")
836
863
            sys.exit(1)
837
 
        except exception.DBError, e:
 
864
        except db_session.DBError, e:
838
865
            print _("DB Error: %s") % e
839
866
            sys.exit(2)
840
867
        except Exception:
845
872
    @args('--name', dest='name', metavar='<name>',
846
873
            help='Name of instance type/flavor')
847
874
    def list(self, name=None):
848
 
        """Lists all active or specific instance types / flavors"""
 
875
        """Lists all active or specific instance types / flavors."""
849
876
        try:
850
877
            if name is None:
851
878
                inst_types = instance_types.get_all_types()
852
879
            else:
853
880
                inst_types = instance_types.get_instance_type_by_name(name)
854
 
        except exception.DBError, e:
 
881
        except db_session.DBError, e:
855
882
            _db_error(e)
856
883
        if isinstance(inst_types.values()[0], dict):
857
884
            for k, v in inst_types.iteritems():
866
893
    @args('--value', dest='value', metavar='<value>',
867
894
           help='The value of the key/value pair')
868
895
    def set_key(self, name, key, value=None):
869
 
        """Add key/value pair to specified instance type's extra_specs"""
 
896
        """Add key/value pair to specified instance type's extra_specs."""
870
897
        try:
871
898
            try:
872
899
                inst_type = instance_types.get_instance_type_by_name(name)
882
909
                            ext_spec)
883
910
            print _("Key %(key)s set to %(value)s on instance"
884
911
                    " type %(name)s") % locals()
885
 
        except exception.DBError, e:
 
912
        except db_session.DBError, e:
886
913
            _db_error(e)
887
914
 
888
915
    @args('--name', dest='name', metavar='<name>',
890
917
    @args('--key', dest='key', metavar='<key>',
891
918
           help='The key to be deleted')
892
919
    def unset_key(self, name, key):
893
 
        """Delete the specified extra spec for instance type"""
 
920
        """Delete the specified extra spec for instance type."""
894
921
        try:
895
922
            try:
896
923
                inst_type = instance_types.get_instance_type_by_name(name)
905
932
                        key)
906
933
 
907
934
            print _("Key %(key)s on instance type %(name)s unset") % locals()
908
 
        except exception.DBError, e:
 
935
        except db_session.DBError, e:
909
936
            _db_error(e)
910
937
 
911
938
 
970
997
 
971
998
 
972
999
class GetLogCommands(object):
973
 
    """Get logging information"""
 
1000
    """Get logging information."""
974
1001
 
975
1002
    def errors(self):
976
 
        """Get all of the errors from the log files"""
 
1003
        """Get all of the errors from the log files."""
977
1004
        error_found = 0
978
1005
        if CONF.log_dir:
979
1006
            logs = [x for x in os.listdir(CONF.log_dir) if x.endswith('.log')]
994
1021
            print _('No errors in logfiles!')
995
1022
 
996
1023
    def syslog(self, num_entries=10):
997
 
        """Get <num_entries> of the nova syslog events"""
 
1024
        """Get <num_entries> of the nova syslog events."""
998
1025
        entries = int(num_entries)
999
1026
        count = 0
1000
1027
        log_file = ''
1059
1086
        ctxt = context.get_admin_context()
1060
1087
        db.cell_create(ctxt, values)
1061
1088
 
1062
 
    @args('--cell_id', dest='cell_id', metavar='<cell_id>',
1063
 
         help='ID of the cell to delete')
1064
 
    def delete(self, cell_id):
 
1089
    @args('--cell_name', dest='cell_name', metavar='<cell_name>',
 
1090
         help='Name of the cell to delete')
 
1091
    def delete(self, cell_name):
1065
1092
        ctxt = context.get_admin_context()
1066
 
        db.cell_delete(ctxt, cell_id)
 
1093
        db.cell_delete(ctxt, cell_name)
1067
1094
 
1068
1095
    def list(self):
1069
1096
        ctxt = context.get_admin_context()
1131
1158
 
1132
1159
            action_kwargs = []
1133
1160
            for args, kwargs in getattr(action_fn, 'args', []):
1134
 
                action_kwargs.append(kwargs['dest'])
1135
 
                kwargs['dest'] = 'action_kwarg_' + kwargs['dest']
 
1161
                if kwargs['dest'].startswith('action_kwarg_'):
 
1162
                    action_kwargs.append(
 
1163
                            kwargs['dest'][len('action_kwarg_'):])
 
1164
                else:
 
1165
                    action_kwargs.append(kwargs['dest'])
 
1166
                    kwargs['dest'] = 'action_kwarg_' + kwargs['dest']
 
1167
 
1136
1168
                parser.add_argument(*args, **kwargs)
1137
1169
 
1138
1170
            parser.set_defaults(action_fn=action_fn)