diff --git a/azure-cli.pyproj b/azure-cli.pyproj
index 0fa304524fa..4b08683558d 100644
--- a/azure-cli.pyproj
+++ b/azure-cli.pyproj
@@ -14,6 +14,9 @@
Standard Python launcher
{1dd9c42b-5980-42ce-a2c3-46d3bf0eede4}
3.5
+
+
+ False
@@ -25,12 +28,19 @@
+
+
+
+
Code
+
+ Code
+
Code
@@ -43,6 +53,7 @@
Code
+
Code
diff --git a/src/azure/cli/_argparse.py b/src/azure/cli/_argparse.py
index 5e0e7f9c3b9..2e46c9186f4 100644
--- a/src/azure/cli/_argparse.py
+++ b/src/azure/cli/_argparse.py
@@ -208,7 +208,7 @@ def not_global(a):
return handler(parsed, others)
except IncorrectUsageError as ex:
print(str(ex), file=out)
- return self.display_usage(nouns, m, args, out)
+ return self._display_usage(nouns, m, args, out)
finally:
sys.stdout = old_stdout
diff --git a/src/azure/cli/commands/__init__.py b/src/azure/cli/commands/__init__.py
index df622e9c0a7..f4172e18b04 100644
--- a/src/azure/cli/commands/__init__.py
+++ b/src/azure/cli/commands/__init__.py
@@ -3,11 +3,13 @@
# TODO: Alternatively, simply scan the directory for all modules
COMMAND_MODULES = [
+ 'account',
'login',
'logout',
- 'account',
+ 'network',
+ 'resourcegroup',
'storage',
- 'resourcegroup'
+ 'vm',
]
_COMMANDS = {}
diff --git a/src/azure/cli/commands/_auto_command.py b/src/azure/cli/commands/_auto_command.py
new file mode 100644
index 00000000000..e79f8f28e2d
--- /dev/null
+++ b/src/azure/cli/commands/_auto_command.py
@@ -0,0 +1,58 @@
+import inspect
+from msrest import Serializer
+from ..commands import command, description, option
+from azure.cli._argparse import IncorrectUsageError
+
+def _decorate_command(name, func):
+ return command(name)(func)
+
+def _decorate_description(desc, func):
+ return description(desc)(func)
+
+def _decorate_option(spec, descr, func):
+ return option(spec, descr)(func)
+
+def _make_func(client_factory, member_name, return_type_name, unbound_func):
+ def call_client(args, unexpected): #pylint: disable=unused-argument
+ client = client_factory()
+ ops_instance = getattr(client, member_name)
+ try:
+ result = unbound_func(ops_instance, **args)
+ if not return_type_name:
+ return {}
+ return Serializer().serialize_data(result, return_type_name)
+ except TypeError as exception:
+ # TODO: Evaluate required/missing parameters and provide specific
+ # usage for missing params...
+ raise IncorrectUsageError(exception)
+
+ return call_client
+
+def _option_description(operation, arg):
+ """Pull out parameter help from doccomments of the command
+ """
+ # TODO: We are currently doing this for every option/argument.
+ # We should do it (at most) once for a given command...
+ return ' '.join(l.split(':')[-1] for l in inspect.getdoc(operation).splitlines()
+ if l.startswith(':param') and arg + ':' in l)
+
+EXCLUDED_PARAMS = frozenset(['self', 'raw', 'custom_headers', 'operation_config'])
+
+def operation_builder(package_name, resource_type, member_name, client_type, operations):
+ for operation, return_type_name in operations:
+ opname = operation.__name__
+ func = _make_func(client_type, member_name, return_type_name, operation)
+ func = _decorate_command(' '.join([package_name, resource_type, opname]), func)
+
+ args = []
+ try:
+ # only supported in python3 - falling back to argspec if not available
+ sig = inspect.signature(operation)
+ args = sig.parameters
+ except AttributeError:
+ sig = inspect.getargspec(operation) #pylint: disable=deprecated-method
+ args = sig.args
+
+ for arg in [a for a in args if not a in EXCLUDED_PARAMS]:
+ spec = '--%s <%s>' % (arg, arg)
+ func = _decorate_option(spec, _option_description(operation, arg), func=func)
diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py
new file mode 100644
index 00000000000..08fff22a772
--- /dev/null
+++ b/src/azure/cli/commands/network.py
@@ -0,0 +1,241 @@
+from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration
+from azure.mgmt.network.operations import (ApplicationGatewaysOperations,
+ ExpressRouteCircuitAuthorizationsOperations,
+ ExpressRouteCircuitPeeringsOperations,
+ ExpressRouteCircuitsOperations,
+ ExpressRouteServiceProvidersOperations,
+ LoadBalancersOperations,
+ LocalNetworkGatewaysOperations,
+ NetworkInterfacesOperations,
+ NetworkSecurityGroupsOperations,
+ PublicIPAddressesOperations,
+ RouteTablesOperations,
+ RoutesOperations,
+ SecurityRulesOperations,
+ SubnetsOperations,
+ UsagesOperations,
+ VirtualNetworkGatewayConnectionsOperations,
+ VirtualNetworkGatewaysOperations,
+ VirtualNetworksOperations)
+
+from ._command_creation import get_service_client
+from ..commands import _auto_command
+
+def _network_client_factory():
+ return get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration)
+
+# pylint: disable=line-too-long
+# Application gateways
+_auto_command.operation_builder("network",
+ "appgateway",
+ "application_gateways",
+ _network_client_factory,
+ [
+ (ApplicationGatewaysOperations.delete, None),
+ (ApplicationGatewaysOperations.get, 'ApplicationGateway'),
+ (ApplicationGatewaysOperations.list, '[ApplicationGateway]'),
+ (ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'),
+ (ApplicationGatewaysOperations.start, None),
+ (ApplicationGatewaysOperations.stop, None),
+ ])
+
+# ExpressRouteCircuitAuthorizationsOperations
+_auto_command.operation_builder("network",
+ "expressroutecircuitauth",
+ "express_route_circuit_authorizations",
+ _network_client_factory,
+ [
+ (ExpressRouteCircuitAuthorizationsOperations.delete, None),
+ (ExpressRouteCircuitAuthorizationsOperations.get, 'ExpressRouteCircuitAuthorization'),
+ (ExpressRouteCircuitAuthorizationsOperations.list, '[ExpressRouteCircuitAuthorization]'),
+ ])
+
+# ExpressRouteCircuitPeeringsOperations
+_auto_command.operation_builder("network",
+ "expressroutecircuitpeering",
+ "express_route_circuit_peerings",
+ _network_client_factory,
+ [
+ (ExpressRouteCircuitPeeringsOperations.delete, None),
+ (ExpressRouteCircuitPeeringsOperations.get, 'ExpressRouteCircuitPeering'),
+ (ExpressRouteCircuitPeeringsOperations.list, '[ExpressRouteCircuitPeering]'),
+ ])
+
+# ExpressRouteCircuitsOperations
+_auto_command.operation_builder("network",
+ "expressroutecircuit",
+ "express_route_circuits",
+ _network_client_factory,
+ [
+ (ExpressRouteCircuitsOperations.delete, None),
+ (ExpressRouteCircuitsOperations.get, 'ExpressRouteCircuit'),
+ (ExpressRouteCircuitsOperations.list_arp_table, '[ExpressRouteCircuitArpTable]'),
+ (ExpressRouteCircuitsOperations.list_routes_table, '[ExpressRouteCircuitRoutesTable]'),
+ (ExpressRouteCircuitsOperations.list_stats, '[ExpressRouteCircuitStats]'),
+ (ExpressRouteCircuitsOperations.list, '[ExpressRouteCircuit]'),
+ (ExpressRouteCircuitsOperations.list_all, '[ExpressRouteCircuit]'),
+ ])
+
+# ExpressRouteServiceProvidersOperations
+_auto_command.operation_builder("network",
+ "expressroutesp",
+ "express_route_service_providers",
+ _network_client_factory,
+ [
+ (ExpressRouteServiceProvidersOperations.list, '[ExpressRouteServiceProvider]'),
+ ])
+
+# LoadBalancersOperations
+_auto_command.operation_builder("network",
+ "lb",
+ "load_balancers",
+ _network_client_factory,
+ [
+ (LoadBalancersOperations.delete, None),
+ (LoadBalancersOperations.get, 'LoadBalancer'),
+ (LoadBalancersOperations.list_all, '[LoadBalancer]'),
+ (LoadBalancersOperations.list, '[LoadBalancer]'),
+ ])
+
+# LocalNetworkGatewaysOperations
+_auto_command.operation_builder("network",
+ "localgateways",
+ "local_network_gateways",
+ _network_client_factory,
+ [
+ (LocalNetworkGatewaysOperations.get, 'LocalNetworkGateway'),
+ (LocalNetworkGatewaysOperations.delete, None),
+ (LocalNetworkGatewaysOperations.list, '[LocalNetworkGateway]'),
+ ])
+
+
+# NetworkInterfacesOperations
+_auto_command.operation_builder("network",
+ "nic",
+ "network_interfaces",
+ _network_client_factory,
+ [
+ (NetworkInterfacesOperations.delete, None),
+ (NetworkInterfacesOperations.get, 'NetworkInterface'),
+ (NetworkInterfacesOperations.list_virtual_machine_scale_set_vm_network_interfaces, '[NetworkInterface]'),
+ (NetworkInterfacesOperations.list_virtual_machine_scale_set_network_interfaces, '[NetworkInterface]'),
+ (NetworkInterfacesOperations.get_virtual_machine_scale_set_network_interface, 'NetworkInterface'),
+ (NetworkInterfacesOperations.list_all, '[NetworkInterface]'),
+ (NetworkInterfacesOperations.list, '[NetworkInterface]'),
+ ])
+
+# NetworkSecurityGroupsOperations
+_auto_command.operation_builder("network",
+ "securitygroup",
+ "network_security_groups",
+ _network_client_factory,
+ [
+ (NetworkSecurityGroupsOperations.delete, None),
+ (NetworkSecurityGroupsOperations.delete, 'NetworkSecurityGroup'),
+ (NetworkSecurityGroupsOperations.list_all, '[NetworkSecurityGroup]'),
+ (NetworkSecurityGroupsOperations.list, '[NetworkSecurityGroup]'),
+ ])
+
+# PublicIPAddressesOperations
+_auto_command.operation_builder("network",
+ "publicipaddress",
+ "public_ip_addresses",
+ _network_client_factory,
+ [
+ (PublicIPAddressesOperations.delete, None),
+ (PublicIPAddressesOperations.get, 'PublicIPAddress'),
+ (PublicIPAddressesOperations.list_all, '[PublicIPAddress]'),
+ (PublicIPAddressesOperations.list, '[PublicIPAddress]'),
+ ])
+
+# RouteTablesOperations
+_auto_command.operation_builder("network",
+ "routetable",
+ "route_tables",
+ _network_client_factory,
+ [
+ (RouteTablesOperations.delete, None),
+ (RouteTablesOperations.get, 'RouteTable'),
+ (RouteTablesOperations.list, '[RouteTable]'),
+ (RouteTablesOperations.list_all, '[RouteTable]'),
+ ])
+
+# RoutesOperations
+_auto_command.operation_builder("network",
+ "routeoperation",
+ "routes",
+ _network_client_factory,
+ [
+ (RoutesOperations.delete, None),
+ (RoutesOperations.get, 'Route'),
+ (RoutesOperations.list, '[Route]'),
+ ])
+
+# SecurityRulesOperations
+_auto_command.operation_builder("network",
+ "securityrules",
+ "security_rules",
+ _network_client_factory,
+ [
+ (SecurityRulesOperations.delete, None),
+ (SecurityRulesOperations.get, 'SecurityRule'),
+ (SecurityRulesOperations.list, '[SecurityRule]'),
+ ])
+
+# SubnetsOperations
+_auto_command.operation_builder("network",
+ "subnet",
+ "subnets",
+ _network_client_factory,
+ [
+ (SubnetsOperations.delete, None),
+ (SubnetsOperations.get, 'Subnet'),
+ (SubnetsOperations.list, '[Subnet]'),
+ ])
+
+# UsagesOperations
+_auto_command.operation_builder("network",
+ "usage",
+ "usages",
+ _network_client_factory,
+ [
+ (UsagesOperations.list, '[Usage]'),
+ ])
+
+# VirtualNetworkGatewayConnectionsOperations
+_auto_command.operation_builder("network",
+ "vnetgatewayconnection",
+ "virtual_network_gateway_connections",
+ _network_client_factory,
+ [
+ (VirtualNetworkGatewayConnectionsOperations.delete, None),
+ (VirtualNetworkGatewayConnectionsOperations.get, 'VirtualNetworkGatewayConnection'),
+ (VirtualNetworkGatewayConnectionsOperations.get_shared_key, 'ConnectionSharedKeyResult'),
+ (VirtualNetworkGatewayConnectionsOperations.list, '[VirtualNetworkGatewayConnection]'),
+ (VirtualNetworkGatewayConnectionsOperations.reset_shared_key, 'ConnectionResetSharedKey'),
+ (VirtualNetworkGatewayConnectionsOperations.set_shared_key, 'ConnectionSharedKey'),
+ ])
+
+# VirtualNetworkGatewaysOperations
+_auto_command.operation_builder("network",
+ "vnetgateway",
+ "virtual_network_gateways",
+ _network_client_factory,
+ [
+ (VirtualNetworkGatewaysOperations.delete, None),
+ (VirtualNetworkGatewaysOperations.get, 'VirtualNetworkGateway'),
+ (VirtualNetworkGatewaysOperations.list, '[VirtualNetworkGateway]'),
+ (VirtualNetworkGatewaysOperations.reset, 'VirtualNetworkGateway'),
+ ])
+
+# VirtualNetworksOperations
+_auto_command.operation_builder("network",
+ "vnet",
+ "virtual_networks",
+ _network_client_factory,
+ [
+ (VirtualNetworksOperations.delete, None),
+ (VirtualNetworksOperations.get, 'VirtualNetwork'),
+ (VirtualNetworksOperations.list, '[VirtualNetwork]'),
+ (VirtualNetworksOperations.list_all, '[VirtualNetwork]'),
+ ])
diff --git a/src/azure/cli/commands/vm.py b/src/azure/cli/commands/vm.py
new file mode 100644
index 00000000000..3cd18407c5f
--- /dev/null
+++ b/src/azure/cli/commands/vm.py
@@ -0,0 +1,127 @@
+from azure.mgmt.compute import ComputeManagementClient, ComputeManagementClientConfiguration
+from azure.mgmt.compute.operations import (AvailabilitySetsOperations,
+ VirtualMachineExtensionImagesOperations,
+ VirtualMachineExtensionsOperations,
+ VirtualMachineImagesOperations,
+ UsageOperations,
+ VirtualMachineSizesOperations,
+ VirtualMachinesOperations,
+ VirtualMachineScaleSetsOperations,
+ VirtualMachineScaleSetVMsOperations)
+
+from ._command_creation import get_service_client
+from ..commands import _auto_command
+
+def _compute_client_factory():
+ return get_service_client(ComputeManagementClient, ComputeManagementClientConfiguration)
+
+# pylint: disable=line-too-long
+_auto_command.operation_builder("vm",
+ "availabilityset",
+ "availability_sets",
+ _compute_client_factory,
+ [
+ (AvailabilitySetsOperations.delete, None),
+ (AvailabilitySetsOperations.get, 'AvailabilitySet'),
+ (AvailabilitySetsOperations.list, '[AvailabilitySet]'),
+ (AvailabilitySetsOperations.list_available_sizes, '[VirtualMachineSize]')
+ ])
+
+
+_auto_command.operation_builder("vm",
+ "machineextensionimages",
+ "virtual_machine_extension_images",
+ _compute_client_factory,
+ [
+ (VirtualMachineExtensionImagesOperations.get, 'VirtualMachineExtensionImage'),
+ (VirtualMachineExtensionImagesOperations.list_types, '[VirtualMachineImageResource]'),
+ (VirtualMachineExtensionImagesOperations.list_versions, '[VirtualMachineImageResource]'),
+ ])
+
+_auto_command.operation_builder("vm",
+ "extensions",
+ "virtual_machine_extensions",
+ _compute_client_factory,
+ [
+ (VirtualMachineExtensionsOperations.delete, None),
+ (VirtualMachineExtensionsOperations.get, 'VirtualMachineExtension'),
+ ])
+
+_auto_command.operation_builder("vm",
+ "image",
+ "virtual_machine_images",
+ _compute_client_factory,
+ [
+ (VirtualMachineImagesOperations.get, 'VirtualMachineImage'),
+ (VirtualMachineImagesOperations.list, '[VirtualMachineImageResource]'),
+ (VirtualMachineImagesOperations.list_offers, '[VirtualMachineImageResource]'),
+ (VirtualMachineImagesOperations.list_publishers, '[VirtualMachineImageResource]'),
+ (VirtualMachineImagesOperations.list_skus, '[VirtualMachineImageResource]'),
+ ])
+
+_auto_command.operation_builder("vm",
+ "usage",
+ "usage",
+ _compute_client_factory,
+ [
+ (UsageOperations.list, '[Usage]'),
+ ])
+
+_auto_command.operation_builder("vm",
+ "size",
+ "virtual_machine_sizes",
+ _compute_client_factory,
+ [
+ (VirtualMachineSizesOperations.list, '[VirtualMachineSize]'),
+ ])
+
+_auto_command.operation_builder("vm",
+ "",
+ "virtual_machines",
+ _compute_client_factory,
+ [
+ (VirtualMachinesOperations.delete, None),
+ (VirtualMachinesOperations.deallocate, None),
+ (VirtualMachinesOperations.generalize, None),
+ (VirtualMachinesOperations.get, 'VirtualMachine'),
+ (VirtualMachinesOperations.list, '[VirtualMachine]'),
+ (VirtualMachinesOperations.list_all, '[VirtualMachine]'),
+ (VirtualMachinesOperations.list_available_sizes, '[VirtualMachineSize]'),
+ (VirtualMachinesOperations.power_off, None),
+ (VirtualMachinesOperations.restart, None),
+ (VirtualMachinesOperations.start, None),
+ ])
+
+_auto_command.operation_builder("vm",
+ "scaleset",
+ "virtual_machine_scale_sets",
+ _compute_client_factory,
+ [
+ (VirtualMachineScaleSetsOperations.deallocate, None),
+ (VirtualMachineScaleSetsOperations.delete, None),
+ (VirtualMachineScaleSetsOperations.get, 'VirtualMachineScaleSet'),
+ (VirtualMachineScaleSetsOperations.delete_instances, None),
+ (VirtualMachineScaleSetsOperations.get_instance_view, 'VirtualMachineScaleSetInstanceView'),
+ (VirtualMachineScaleSetsOperations.list, '[VirtualMachineScaleSet]'),
+ (VirtualMachineScaleSetsOperations.list_all, '[VirtualMachineScaleSet]'),
+ (VirtualMachineScaleSetsOperations.list_skus, '[VirtualMachineScaleSet]'),
+ (VirtualMachineScaleSetsOperations.power_off, None),
+ (VirtualMachineScaleSetsOperations.restart, None),
+ (VirtualMachineScaleSetsOperations.start, None),
+ (VirtualMachineScaleSetsOperations.update_instances, None),
+ ])
+
+_auto_command.operation_builder("vm",
+ "vmscaleset",
+ "virtual_machine_scale_set_vms",
+ _compute_client_factory,
+ [
+ (VirtualMachineScaleSetVMsOperations.deallocate, None),
+ (VirtualMachineScaleSetVMsOperations.delete, None),
+ (VirtualMachineScaleSetVMsOperations.get, None),
+ (VirtualMachineScaleSetVMsOperations.get_instance_view, 'VirtualMachineScaleSetVMInstanceView'),
+ (VirtualMachineScaleSetVMsOperations.list, '[VirtualMachineScaleSetVM]'),
+ (VirtualMachineScaleSetVMsOperations.power_off, None),
+ (VirtualMachineScaleSetVMsOperations.restart, None),
+ (VirtualMachineScaleSetVMsOperations.start, None),
+ ])
diff --git a/src/azure/cli/tests/test_autocommand.py b/src/azure/cli/tests/test_autocommand.py
new file mode 100644
index 00000000000..ee403cae0f0
--- /dev/null
+++ b/src/azure/cli/tests/test_autocommand.py
@@ -0,0 +1,79 @@
+import logging
+import unittest
+
+from azure.cli.commands._auto_command import (_decorate_command,
+ _decorate_option)
+
+from azure.cli.commands import _COMMANDS
+
+class Test_autocommand(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ # Ensure initialization has occurred correctly
+ import azure.cli.main
+ logging.basicConfig(level=logging.DEBUG)
+
+ @classmethod
+ def tearDownClass(cls):
+ logging.shutdown()
+
+ def test_raw_register_command(self):
+ command_name = 'da command'
+ def testfunc():
+ return testfunc
+
+ # Run test code
+ _decorate_command(command_name, testfunc)
+
+ # Verify
+ registered_command = _COMMANDS.get(testfunc, None)
+ self.assertIsNotNone(registered_command)
+ self.assertFalse('args' in registered_command.keys())
+ self.assertEqual(registered_command['name'], command_name)
+
+ def test_raw_register_command_with_one_option(self):
+ command_name = 'da command with one arg'
+ def testfunc():
+ return testfunc
+
+ # Run test code
+ func = _decorate_command(command_name, testfunc)
+ spec = '--tre '
+ desc = 'Kronor'
+ func = _decorate_option(spec, desc, func)
+
+ # Verify
+ registered_command = _COMMANDS.get(testfunc, None)
+ self.assertIsNotNone(registered_command)
+ self.assertEqual(registered_command['name'], command_name)
+ self.assertEqual(len(registered_command['args']), 1)
+ self.assertEqual(registered_command['args'][0], (spec, desc))
+
+ def test_load_test_commands(self):
+ import sys
+ from azure.cli._argparse import ArgumentParser
+ from azure.cli.commands import add_to_parser
+
+ # sneaky trick to avoid loading any command modules...
+ sys.modules['azure.cli.commands.test'] = sys
+
+ command_name = 'da command with one arg and unexpected'
+ def testfunc(args, _):
+ # Check that the argument passing actually works...
+ self.assertEqual(args['tre'], 'wombat')
+ return testfunc
+
+ # Run test code
+ func = _decorate_command(command_name, testfunc)
+ spec = '--tre '
+ desc = 'Kronor'
+ func = _decorate_option(spec, desc, func)
+
+ p = ArgumentParser('automcommandtest')
+ add_to_parser(p, 'test')
+
+ result = p.execute(command_name.split(' ') + '--tre wombat'.split(' '))
+ self.assertEqual(result, func)
+
+if __name__ == '__main__':
+ unittest.main()