From 1db6dafcabe68aa89bf3a8fdc2f13874b6aea52d Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Tue, 1 Mar 2016 12:18:23 -0800 Subject: [PATCH 01/19] Hand-authored network create commands --- src/azure/cli/commands/network.py | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/azure/cli/commands/network.py diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py new file mode 100644 index 00000000000..d8c00615049 --- /dev/null +++ b/src/azure/cli/commands/network.py @@ -0,0 +1,69 @@ +from msrest import Serializer + +from ..commands import command, description, option +from ._command_creation import get_service_client + +@command('network vnet create') +@description(_('Create or update a virtual network (VNet)')) +@option('--resource-group -g ', _('the resource group name')) #required +@option('--name -n ', _('the VNet name')) #required +@option('--location -l ', _('the VNet location')) #required +@option('--address-space -a ', _('the VNet address-space in CIDR notation')) #required +@option('--dns-servers -d ', _('the VNet DNS servers')) +def create_update_vnet(args, unexpected): + from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration + from azure.mgmt.network.models import VirtualNetwork, AddressSpace, DhcpOptions + + resource_group = args.get('resource-group') + name = args.get('name') + location = args.get('location') + address_space = AddressSpace(address_prefixes = [args.get('address-space')]) + dhcp_options = DhcpOptions(dns_servers = args.get('dns-servers')) + + vnet_settings = VirtualNetwork(location = location, + address_space = address_space, + dhcp_options = dhcp_options) + + smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) + poller = smc.virtual_networks.create_or_update(resource_group, name, vnet_settings) + return Serializer().serialize_data(poller.result(), "VirtualNetwork") + +@command('network subnet create') +@description(_('Create or update a virtual network (VNet) subnet')) +@option('--resource-group -g ', _('the the resource group name')) #required +@option('--name -n ', _('the the subnet name')) #required +@option('--vnet -v ', _('the name of the subnet vnet')) #required +@option('--address-prefix -a ', _('the the address prefix in CIDR format')) #required +@option('--ip-name -ipn ', _('the IP address configuration name')) +@option('--ip-private-address -ippr ', _('the private IP address')) +@option('--ip-allocation-method -ipa ', _('the IP address allocation method')) +@option('--ip-public-address -ippu ', _('the public IP address')) +def create_update_subnet(args, unexpected): + from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration + from azure.mgmt.network.models import Subnet, IPConfiguration + + resource_group = args.get('resource-group') + vnet = args.get('vnet') + name = args.get('name') + address_prefix = args.get('address-prefix') + ip_name = args.get('ip-name') + ip_private_address = args.get('ip-private-address') + ip_allocation_method = args.get('ip-allocation-method') + ip_public_address = args.get('ip-public-address') + + ip_configuration = None + #IPConfiguration(subnet = name, + # name = ip_name, + # private_ip_address = ip_private_address, + # private_ip_allocation_method = ip_allocation_method, + # public_ip_address = ip_public_address) + + subnet_settings = Subnet(name = name, + address_prefix = address_prefix) + #ip_configurations = [ip_configuration]) + + smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) + poller = smc.subnets.create_or_update(resource_group, vnet, name, subnet_settings) + return Serializer().serialize_data(poller.result(), "Subnet") + + From e2c7914644284f2b82ae1784660029a0e8a46a58 Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Tue, 1 Mar 2016 12:28:19 -0800 Subject: [PATCH 02/19] add project file --- azure-cli.pyproj | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-cli.pyproj b/azure-cli.pyproj index 0fa304524fa..b58f4557632 100644 --- a/azure-cli.pyproj +++ b/azure-cli.pyproj @@ -25,6 +25,7 @@ + From f19617a3ce4b30a44a7d92686ca660da08a1248d Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 15:12:37 -0800 Subject: [PATCH 03/19] merge imports --- src/azure/cli/commands/network.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index e1cac089c2d..8a9a0887351 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -20,6 +20,9 @@ from ._command_creation import get_service_client from ..commands import _auto_command +from ..commands import command, description, option +from msrest import Serializer + def _network_client_factory(): return get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) @@ -239,10 +242,6 @@ def _network_client_factory(): (VirtualNetworksOperations.list, '[VirtualNetwork]'), (VirtualNetworksOperations.list_all, '[VirtualNetwork]'), ]) -from msrest import Serializer - -from ..commands import command, description, option -from ._command_creation import get_service_client @command('network vnet create') @description(_('Create or update a virtual network (VNet)')) From 5e247cc85614bfd5688a5023b9c61dc32c3e712e Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 15:43:43 -0800 Subject: [PATCH 04/19] polish commands and project file --- azure-cli.pyproj | 29 ++++------------ src/azure/cli/commands/network.py | 55 ++++++++++++++++--------------- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/azure-cli.pyproj b/azure-cli.pyproj index f029358170c..28a4caa8398 100644 --- a/azure-cli.pyproj +++ b/azure-cli.pyproj @@ -12,7 +12,7 @@ . {888888a0-9f3d-457c-b088-3a5042f75d52} Standard Python launcher - {4ae3497d-f45c-4ec2-9e26-57476ef276a0} + {1dd9c42b-5980-42ce-a2c3-46d3bf0eede4} 3.5 @@ -25,7 +25,12 @@ + + + + + @@ -54,28 +59,6 @@ - - {83c20e12-84e3-4c10-a1ba-466d2b57483d} - {2af0f10d-7135-4994-9156-5d01c9c11b7e} - 2.7 - env27b (Python 2.7) - Scripts\python.exe - Scripts\pythonw.exe - Lib\ - PYTHONPATH - X86 - - - {4ae3497d-f45c-4ec2-9e26-57476ef276a0} - {2af0f10d-7135-4994-9156-5d01c9c11b7e} - 3.5 - env35d (Python 3.5) - Scripts\python.exe - Scripts\pythonw.exe - Lib\ - PYTHONPATH - X86 - {1dd9c42b-5980-42ce-a2c3-46d3bf0eede4} {2af0f10d-7135-4994-9156-5d01c9c11b7e} diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index 1ec5db3edf5..e24a35c8505 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -246,12 +246,12 @@ def _network_client_factory(): ]) @command('network vnet create') -@description(_('Create or update a virtual network (VNet)')) -@option('--resource-group -g ', _('the resource group name')) #required -@option('--name -n ', _('the VNet name')) #required -@option('--location -l ', _('the VNet location')) #required -@option('--address-space -a ', _('the VNet address-space in CIDR notation')) #required -@option('--dns-servers -d ', _('the VNet DNS servers')) +@description(L('Create or update a virtual network (VNet)')) +@option('--resource-group -g ', L('the resource group name')) #required +@option('--name -n ', L('the VNet name')) #required +@option('--location -l ', L('the VNet location')) #required +@option('--address-space -a ', L('the VNet address-space in CIDR notation')) #required +@option('--dns-servers -d ', L('the VNet DNS servers')) def create_update_vnet(args, unexpected): from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration from azure.mgmt.network.models import VirtualNetwork, AddressSpace, DhcpOptions @@ -271,15 +271,16 @@ def create_update_vnet(args, unexpected): return Serializer().serialize_data(poller.result(), "VirtualNetwork") @command('network subnet create') -@description(_('Create or update a virtual network (VNet) subnet')) -@option('--resource-group -g ', _('the the resource group name')) #required -@option('--name -n ', _('the the subnet name')) #required -@option('--vnet -v ', _('the name of the subnet vnet')) #required -@option('--address-prefix -a ', _('the the address prefix in CIDR format')) #required -@option('--ip-name -ipn ', _('the IP address configuration name')) -@option('--ip-private-address -ippr ', _('the private IP address')) -@option('--ip-allocation-method -ipa ', _('the IP address allocation method')) -@option('--ip-public-address -ippu ', _('the public IP address')) +@description(L('Create or update a virtual network (VNet) subnet')) +@option('--resource-group -g ', L('the the resource group name')) #required +@option('--name -n ', L('the the subnet name')) #required +@option('--vnet -v ', L('the name of the subnet vnet')) #required +@option('--address-prefix -a ', L('the the address prefix in CIDR format')) #required +# TODO: setting the IPConfiguration fails, will contact owning team +#@option('--ip-name -ipn ', L('the IP address configuration name')) +#@option('--ip-private-address -ippa ', L('the private IP address')) +#@option('--ip-allocation-method -ipam ', L('the IP address allocation method')) +#@option('--ip-public-address -ipa ', L('the public IP address')) def create_update_subnet(args, unexpected): from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration from azure.mgmt.network.models import Subnet, IPConfiguration @@ -288,20 +289,22 @@ def create_update_subnet(args, unexpected): vnet = args.get('vnet') name = args.get('name') address_prefix = args.get('address-prefix') - ip_name = args.get('ip-name') - ip_private_address = args.get('ip-private-address') - ip_allocation_method = args.get('ip-allocation-method') - ip_public_address = args.get('ip-public-address') - - ip_configuration = None - #IPConfiguration(subnet = name, - # name = ip_name, - # private_ip_address = ip_private_address, - # private_ip_allocation_method = ip_allocation_method, - # public_ip_address = ip_public_address) + # TODO: setting the IPConfiguration fails, will contact owning team + #ip_name = args.get('ip-name') + #ip_private_address = args.get('ip-private-address') + #ip_allocation_method = args.get('ip-allocation-method') + #ip_public_address = args.get('ip-public-address') + + # TODO: setting the IPConfiguration fails, will contact owning team + #ip_configuration = IPConfiguration(subnet = name, + # name = ip_name, + # private_ip_address = ip_private_address, + # private_ip_allocation_method = ip_allocation_method, + # public_ip_address = ip_public_address) subnet_settings = Subnet(name = name, address_prefix = address_prefix) + # TODO: setting the IPConfiguration fails, will contact owning team #ip_configurations = [ip_configuration]) smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) From 4b99a11cb627cab6a037dc562dffc64692294a07 Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 15:48:15 -0800 Subject: [PATCH 05/19] remove weird whitespaces --- src/azure/cli/commands/network.py | 320 +++++++++++++++--------------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index e24a35c8505..e5493f841a1 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -32,218 +32,218 @@ def _network_client_factory(): # pylint: disable=line-too-long # Application gateways build_operation("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, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), - ]) + "appgateway", + "application_gateways", + _network_client_factory, + [ + (ApplicationGatewaysOperations.delete, None), + (ApplicationGatewaysOperations.get, 'ApplicationGateway'), + (ApplicationGatewaysOperations.list, '[ApplicationGateway]'), + (ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'), + (ApplicationGatewaysOperations.start, None), + (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), + ]) # ExpressRouteCircuitAuthorizationsOperations build_operation("network", - "expressroutecircuitauth", - "express_route_circuit_authorizations", - _network_client_factory, - [ - (ExpressRouteCircuitAuthorizationsOperations.delete, None), - (ExpressRouteCircuitAuthorizationsOperations.get, 'ExpressRouteCircuitAuthorization'), - (ExpressRouteCircuitAuthorizationsOperations.list, '[ExpressRouteCircuitAuthorization]'), - ]) + "expressroutecircuitauth", + "express_route_circuit_authorizations", + _network_client_factory, + [ + (ExpressRouteCircuitAuthorizationsOperations.delete, None), + (ExpressRouteCircuitAuthorizationsOperations.get, 'ExpressRouteCircuitAuthorization'), + (ExpressRouteCircuitAuthorizationsOperations.list, '[ExpressRouteCircuitAuthorization]'), + ]) # ExpressRouteCircuitPeeringsOperations build_operation("network", - "expressroutecircuitpeering", - "express_route_circuit_peerings", - _network_client_factory, - [ - (ExpressRouteCircuitPeeringsOperations.delete, None), - (ExpressRouteCircuitPeeringsOperations.get, 'ExpressRouteCircuitPeering'), - (ExpressRouteCircuitPeeringsOperations.list, '[ExpressRouteCircuitPeering]'), - ]) + "expressroutecircuitpeering", + "express_route_circuit_peerings", + _network_client_factory, + [ + (ExpressRouteCircuitPeeringsOperations.delete, None), + (ExpressRouteCircuitPeeringsOperations.get, 'ExpressRouteCircuitPeering'), + (ExpressRouteCircuitPeeringsOperations.list, '[ExpressRouteCircuitPeering]'), + ]) # ExpressRouteCircuitsOperations build_operation("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]'), - ]) + "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 build_operation("network", - "expressroutesp", - "express_route_service_providers", - _network_client_factory, - [ - (ExpressRouteServiceProvidersOperations.list, '[ExpressRouteServiceProvider]'), - ]) + "expressroutesp", + "express_route_service_providers", + _network_client_factory, + [ + (ExpressRouteServiceProvidersOperations.list, '[ExpressRouteServiceProvider]'), + ]) # LoadBalancersOperations build_operation("network", - "lb", - "load_balancers", - _network_client_factory, - [ - (LoadBalancersOperations.delete, None), - (LoadBalancersOperations.get, 'LoadBalancer'), - (LoadBalancersOperations.list_all, '[LoadBalancer]'), - (LoadBalancersOperations.list, '[LoadBalancer]'), - ]) + "lb", + "load_balancers", + _network_client_factory, + [ + (LoadBalancersOperations.delete, None), + (LoadBalancersOperations.get, 'LoadBalancer'), + (LoadBalancersOperations.list_all, '[LoadBalancer]'), + (LoadBalancersOperations.list, '[LoadBalancer]'), + ]) # LocalNetworkGatewaysOperations build_operation("network", - "localgateways", - "local_network_gateways", - _network_client_factory, - [ - (LocalNetworkGatewaysOperations.get, 'LocalNetworkGateway'), - (LocalNetworkGatewaysOperations.delete, None), - (LocalNetworkGatewaysOperations.list, '[LocalNetworkGateway]'), - ]) + "localgateways", + "local_network_gateways", + _network_client_factory, + [ + (LocalNetworkGatewaysOperations.get, 'LocalNetworkGateway'), + (LocalNetworkGatewaysOperations.delete, None), + (LocalNetworkGatewaysOperations.list, '[LocalNetworkGateway]'), + ]) # NetworkInterfacesOperations build_operation("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]'), - ]) + "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 build_operation("network", - "securitygroup", - "network_security_groups", - _network_client_factory, - [ - (NetworkSecurityGroupsOperations.delete, None), - (NetworkSecurityGroupsOperations.delete, 'NetworkSecurityGroup'), - (NetworkSecurityGroupsOperations.list_all, '[NetworkSecurityGroup]'), - (NetworkSecurityGroupsOperations.list, '[NetworkSecurityGroup]'), - ]) + "securitygroup", + "network_security_groups", + _network_client_factory, + [ + (NetworkSecurityGroupsOperations.delete, None), + (NetworkSecurityGroupsOperations.delete, 'NetworkSecurityGroup'), + (NetworkSecurityGroupsOperations.list_all, '[NetworkSecurityGroup]'), + (NetworkSecurityGroupsOperations.list, '[NetworkSecurityGroup]'), + ]) # PublicIPAddressesOperations build_operation("network", - "publicipaddress", - "public_ip_addresses", - _network_client_factory, - [ - (PublicIPAddressesOperations.delete, None), - (PublicIPAddressesOperations.get, 'PublicIPAddress'), - (PublicIPAddressesOperations.list_all, '[PublicIPAddress]'), - (PublicIPAddressesOperations.list, '[PublicIPAddress]'), - ]) + "publicipaddress", + "public_ip_addresses", + _network_client_factory, + [ + (PublicIPAddressesOperations.delete, None), + (PublicIPAddressesOperations.get, 'PublicIPAddress'), + (PublicIPAddressesOperations.list_all, '[PublicIPAddress]'), + (PublicIPAddressesOperations.list, '[PublicIPAddress]'), + ]) # RouteTablesOperations build_operation("network", - "routetable", - "route_tables", - _network_client_factory, - [ - (RouteTablesOperations.delete, None), - (RouteTablesOperations.get, 'RouteTable'), - (RouteTablesOperations.list, '[RouteTable]'), - (RouteTablesOperations.list_all, '[RouteTable]'), - ]) + "routetable", + "route_tables", + _network_client_factory, + [ + (RouteTablesOperations.delete, None), + (RouteTablesOperations.get, 'RouteTable'), + (RouteTablesOperations.list, '[RouteTable]'), + (RouteTablesOperations.list_all, '[RouteTable]'), + ]) # RoutesOperations build_operation("network", - "routeoperation", - "routes", - _network_client_factory, - [ - (RoutesOperations.delete, None), - (RoutesOperations.get, 'Route'), - (RoutesOperations.list, '[Route]'), - ]) + "routeoperation", + "routes", + _network_client_factory, + [ + (RoutesOperations.delete, None), + (RoutesOperations.get, 'Route'), + (RoutesOperations.list, '[Route]'), + ]) # SecurityRulesOperations build_operation("network", - "securityrules", - "security_rules", - _network_client_factory, - [ - (SecurityRulesOperations.delete, None), - (SecurityRulesOperations.get, 'SecurityRule'), - (SecurityRulesOperations.list, '[SecurityRule]'), - ]) + "securityrules", + "security_rules", + _network_client_factory, + [ + (SecurityRulesOperations.delete, None), + (SecurityRulesOperations.get, 'SecurityRule'), + (SecurityRulesOperations.list, '[SecurityRule]'), + ]) # SubnetsOperations build_operation("network", - "subnet", - "subnets", - _network_client_factory, - [ - (SubnetsOperations.delete, None), - (SubnetsOperations.get, 'Subnet'), - (SubnetsOperations.list, '[Subnet]'), - ]) + "subnet", + "subnets", + _network_client_factory, + [ + (SubnetsOperations.delete, None), + (SubnetsOperations.get, 'Subnet'), + (SubnetsOperations.list, '[Subnet]'), + ]) # UsagesOperations build_operation("network", - "usage", - "usages", - _network_client_factory, - [ - (UsagesOperations.list, '[Usage]'), - ]) + "usage", + "usages", + _network_client_factory, + [ + (UsagesOperations.list, '[Usage]'), + ]) # VirtualNetworkGatewayConnectionsOperations build_operation("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'), - ]) + "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 build_operation("network", - "vnetgateway", - "virtual_network_gateways", - _network_client_factory, - [ - (VirtualNetworkGatewaysOperations.delete, None), - (VirtualNetworkGatewaysOperations.get, 'VirtualNetworkGateway'), - (VirtualNetworkGatewaysOperations.list, '[VirtualNetworkGateway]'), - (VirtualNetworkGatewaysOperations.reset, 'VirtualNetworkGateway'), - ]) + "vnetgateway", + "virtual_network_gateways", + _network_client_factory, + [ + (VirtualNetworkGatewaysOperations.delete, None), + (VirtualNetworkGatewaysOperations.get, 'VirtualNetworkGateway'), + (VirtualNetworkGatewaysOperations.list, '[VirtualNetworkGateway]'), + (VirtualNetworkGatewaysOperations.reset, 'VirtualNetworkGateway'), + ]) # VirtualNetworksOperations build_operation("network", - "vnet", - "virtual_networks", - _network_client_factory, - [ - (VirtualNetworksOperations.delete, None), - (VirtualNetworksOperations.get, 'VirtualNetwork'), - (VirtualNetworksOperations.list, '[VirtualNetwork]'), - (VirtualNetworksOperations.list_all, '[VirtualNetwork]'), - ]) + "vnet", + "virtual_networks", + _network_client_factory, + [ + (VirtualNetworksOperations.delete, None), + (VirtualNetworksOperations.get, 'VirtualNetwork'), + (VirtualNetworksOperations.list, '[VirtualNetwork]'), + (VirtualNetworksOperations.list_all, '[VirtualNetwork]'), + ]) @command('network vnet create') @description(L('Create or update a virtual network (VNet)')) From ce5f90773fa5392fbc38d4cb48a44c254efbd1e9 Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 15:49:13 -0800 Subject: [PATCH 06/19] more whitespace --- src/azure/cli/commands/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index e5493f841a1..d285f802d75 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -41,7 +41,7 @@ def _network_client_factory(): (ApplicationGatewaysOperations.list, '[ApplicationGateway]'), (ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'), (ApplicationGatewaysOperations.start, None), - (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), + (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), ]) # ExpressRouteCircuitAuthorizationsOperations From dec14e325269ab243c285395d0c4122125123cfb Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 16:00:11 -0800 Subject: [PATCH 07/19] fix pylint errors --- src/azure/cli/commands/network.py | 43 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index d285f802d75..2cec7411514 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -1,3 +1,4 @@ +from msrest import Serializer from .._locale import L from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration from azure.mgmt.network.operations import (ApplicationGatewaysOperations, @@ -18,12 +19,16 @@ VirtualNetworkGatewayConnectionsOperations, VirtualNetworkGatewaysOperations, VirtualNetworksOperations) +from azure.mgmt.network.models import (AddressSpace, + DhcpOptions, + # TODO: setting the IPConfiguration fails + #IPConfiguration, + Subnet, + VirtualNetwork) from ._command_creation import get_service_client from ..commands._auto_command import build_operation, LongRunningOperation -from ..commands import _auto_command from ..commands import command, description, option -from msrest import Serializer def _network_client_factory(): @@ -252,19 +257,16 @@ def _network_client_factory(): @option('--location -l ', L('the VNet location')) #required @option('--address-space -a ', L('the VNet address-space in CIDR notation')) #required @option('--dns-servers -d ', L('the VNet DNS servers')) -def create_update_vnet(args, unexpected): - from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration - from azure.mgmt.network.models import VirtualNetwork, AddressSpace, DhcpOptions - +def create_update_vnet(args, unexpected): #pylint: disable=unused-argument resource_group = args.get('resource-group') name = args.get('name') location = args.get('location') - address_space = AddressSpace(address_prefixes = [args.get('address-space')]) - dhcp_options = DhcpOptions(dns_servers = args.get('dns-servers')) + address_space = AddressSpace(address_prefixes=[args.get('address-space')]) + dhcp_options = DhcpOptions(dns_servers=args.get('dns-servers')) - vnet_settings = VirtualNetwork(location = location, - address_space = address_space, - dhcp_options = dhcp_options) + vnet_settings = VirtualNetwork(location=location, + address_space=address_space, + dhcp_options=dhcp_options) smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) poller = smc.virtual_networks.create_or_update(resource_group, name, vnet_settings) @@ -277,14 +279,11 @@ def create_update_vnet(args, unexpected): @option('--vnet -v ', L('the name of the subnet vnet')) #required @option('--address-prefix -a ', L('the the address prefix in CIDR format')) #required # TODO: setting the IPConfiguration fails, will contact owning team -#@option('--ip-name -ipn ', L('the IP address configuration name')) -#@option('--ip-private-address -ippa ', L('the private IP address')) -#@option('--ip-allocation-method -ipam ', L('the IP address allocation method')) -#@option('--ip-public-address -ipa ', L('the public IP address')) -def create_update_subnet(args, unexpected): - from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration - from azure.mgmt.network.models import Subnet, IPConfiguration - +#@option('--ip-name -ipn ', L('the IP address configuration name')) +#@option('--ip-private-address -ippa ', L('the private IP address')) +#@option('--ip-allocation-method -ipam ', L('the IP address allocation method')) +#@option('--ip-public-address -ipa ', L('the public IP address')) +def create_update_subnet(args, unexpected): #pylint: disable=unused-argument resource_group = args.get('resource-group') vnet = args.get('vnet') name = args.get('name') @@ -296,14 +295,14 @@ def create_update_subnet(args, unexpected): #ip_public_address = args.get('ip-public-address') # TODO: setting the IPConfiguration fails, will contact owning team - #ip_configuration = IPConfiguration(subnet = name, + #ip_configuration = IPConfiguration(subnet = name, # name = ip_name, # private_ip_address = ip_private_address, # private_ip_allocation_method = ip_allocation_method, # public_ip_address = ip_public_address) - subnet_settings = Subnet(name = name, - address_prefix = address_prefix) + subnet_settings = Subnet(name=name, + address_prefix=address_prefix) # TODO: setting the IPConfiguration fails, will contact owning team #ip_configurations = [ip_configuration]) From 99d542120203c550b374fdcacbcdbb208c47c9a6 Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Wed, 2 Mar 2016 16:05:11 -0800 Subject: [PATCH 08/19] added required param options --- src/azure/cli/commands/network.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index 2cec7411514..1dd9a8b85da 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -30,7 +30,6 @@ from ..commands._auto_command import build_operation, LongRunningOperation from ..commands import command, description, option - def _network_client_factory(): return get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) @@ -252,10 +251,10 @@ def _network_client_factory(): @command('network vnet create') @description(L('Create or update a virtual network (VNet)')) -@option('--resource-group -g ', L('the resource group name')) #required -@option('--name -n ', L('the VNet name')) #required -@option('--location -l ', L('the VNet location')) #required -@option('--address-space -a ', L('the VNet address-space in CIDR notation')) #required +@option('--resource-group -g ', L('the resource group name'), required=True) +@option('--name -n ', L('the VNet name'), required=True) +@option('--location -l ', L('the VNet location'), required=True) +@option('--address-space -a ', L('the VNet address-space in CIDR notation'), required=True) @option('--dns-servers -d ', L('the VNet DNS servers')) def create_update_vnet(args, unexpected): #pylint: disable=unused-argument resource_group = args.get('resource-group') @@ -274,10 +273,10 @@ def create_update_vnet(args, unexpected): #pylint: disable=unused-argument @command('network subnet create') @description(L('Create or update a virtual network (VNet) subnet')) -@option('--resource-group -g ', L('the the resource group name')) #required -@option('--name -n ', L('the the subnet name')) #required -@option('--vnet -v ', L('the name of the subnet vnet')) #required -@option('--address-prefix -a ', L('the the address prefix in CIDR format')) #required +@option('--resource-group -g ', L('the the resource group name'), required=True) +@option('--name -n ', L('the the subnet name'), required=True) +@option('--vnet -v ', L('the name of the subnet vnet'), required=True) +@option('--address-prefix -a ', L('the the address prefix in CIDR format'), required=True) # TODO: setting the IPConfiguration fails, will contact owning team #@option('--ip-name -ipn ', L('the IP address configuration name')) #@option('--ip-private-address -ippa ', L('the private IP address')) From a279df8b53804635d70fadae6e5615cd7eff0094 Mon Sep 17 00:00:00 2001 From: Johan Stenberg Date: Wed, 2 Mar 2016 18:22:30 -0800 Subject: [PATCH 09/19] Hook up long running operations handler to autocommands --- src/azure/cli/commands/network.py | 36 +++++++++++++++---------------- src/azure/cli/commands/vm.py | 34 ++++++++++++++--------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index 39f0615eb68..99212cdc407 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -32,12 +32,12 @@ def _network_client_factory(): "application_gateways", _network_client_factory, [ - (ApplicationGatewaysOperations.delete, None), + (ApplicationGatewaysOperations.delete, LongRunningOperation(L('Deleting application gateway'), L('Application gateway deleted'))), (ApplicationGatewaysOperations.get, 'ApplicationGateway'), (ApplicationGatewaysOperations.list, '[ApplicationGateway]'), (ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'), - (ApplicationGatewaysOperations.start, None), - (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), + (ApplicationGatewaysOperations.start, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), + (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Stopping application gateway'), L('Application gateway stopped'))), ]) # ExpressRouteCircuitAuthorizationsOperations @@ -46,7 +46,7 @@ def _network_client_factory(): "express_route_circuit_authorizations", _network_client_factory, [ - (ExpressRouteCircuitAuthorizationsOperations.delete, None), + (ExpressRouteCircuitAuthorizationsOperations.delete, LongRunningOperation(L('Deleting express route authorization'), L('Express route authorization deleted'))), (ExpressRouteCircuitAuthorizationsOperations.get, 'ExpressRouteCircuitAuthorization'), (ExpressRouteCircuitAuthorizationsOperations.list, '[ExpressRouteCircuitAuthorization]'), ]) @@ -57,7 +57,7 @@ def _network_client_factory(): "express_route_circuit_peerings", _network_client_factory, [ - (ExpressRouteCircuitPeeringsOperations.delete, None), + (ExpressRouteCircuitPeeringsOperations.delete, LongRunningOperation(L('Deleting express route circuit peering'), L('Express route circuit peering deleted'))), (ExpressRouteCircuitPeeringsOperations.get, 'ExpressRouteCircuitPeering'), (ExpressRouteCircuitPeeringsOperations.list, '[ExpressRouteCircuitPeering]'), ]) @@ -68,7 +68,7 @@ def _network_client_factory(): "express_route_circuits", _network_client_factory, [ - (ExpressRouteCircuitsOperations.delete, None), + (ExpressRouteCircuitsOperations.delete, LongRunningOperation(L('Deleting express route circuit'), L('Express route circuit deleted'))), (ExpressRouteCircuitsOperations.get, 'ExpressRouteCircuit'), (ExpressRouteCircuitsOperations.list_arp_table, '[ExpressRouteCircuitArpTable]'), (ExpressRouteCircuitsOperations.list_routes_table, '[ExpressRouteCircuitRoutesTable]'), @@ -92,7 +92,7 @@ def _network_client_factory(): "load_balancers", _network_client_factory, [ - (LoadBalancersOperations.delete, None), + (LoadBalancersOperations.delete, LongRunningOperation(L('Deleting load balancer'), L('Load balancer deleted'))), (LoadBalancersOperations.get, 'LoadBalancer'), (LoadBalancersOperations.list_all, '[LoadBalancer]'), (LoadBalancersOperations.list, '[LoadBalancer]'), @@ -105,7 +105,7 @@ def _network_client_factory(): _network_client_factory, [ (LocalNetworkGatewaysOperations.get, 'LocalNetworkGateway'), - (LocalNetworkGatewaysOperations.delete, None), + (LocalNetworkGatewaysOperations.delete, LongRunningOperation(L('Deleting local network gateway'), L('Local network gateway deleted'))), (LocalNetworkGatewaysOperations.list, '[LocalNetworkGateway]'), ]) @@ -116,7 +116,7 @@ def _network_client_factory(): "network_interfaces", _network_client_factory, [ - (NetworkInterfacesOperations.delete, None), + (NetworkInterfacesOperations.delete, LongRunningOperation(L('Deleting network interface'), L('Network interface deleted'))), (NetworkInterfacesOperations.get, 'NetworkInterface'), (NetworkInterfacesOperations.list_virtual_machine_scale_set_vm_network_interfaces, '[NetworkInterface]'), (NetworkInterfacesOperations.list_virtual_machine_scale_set_network_interfaces, '[NetworkInterface]'), @@ -131,7 +131,7 @@ def _network_client_factory(): "network_security_groups", _network_client_factory, [ - (NetworkSecurityGroupsOperations.delete, None), + (NetworkSecurityGroupsOperations.delete, LongRunningOperation(L('Deleting network security group'), L('Network security group deleted'))), (NetworkSecurityGroupsOperations.delete, 'NetworkSecurityGroup'), (NetworkSecurityGroupsOperations.list_all, '[NetworkSecurityGroup]'), (NetworkSecurityGroupsOperations.list, '[NetworkSecurityGroup]'), @@ -143,7 +143,7 @@ def _network_client_factory(): "public_ip_addresses", _network_client_factory, [ - (PublicIPAddressesOperations.delete, None), + (PublicIPAddressesOperations.delete, LongRunningOperation(L('Deleting public IP address'), L('Public IP address deleted'))), (PublicIPAddressesOperations.get, 'PublicIPAddress'), (PublicIPAddressesOperations.list_all, '[PublicIPAddress]'), (PublicIPAddressesOperations.list, '[PublicIPAddress]'), @@ -155,7 +155,7 @@ def _network_client_factory(): "route_tables", _network_client_factory, [ - (RouteTablesOperations.delete, None), + (RouteTablesOperations.delete, LongRunningOperation(L('Deleting route table'), L('Route table deleted'))), (RouteTablesOperations.get, 'RouteTable'), (RouteTablesOperations.list, '[RouteTable]'), (RouteTablesOperations.list_all, '[RouteTable]'), @@ -167,7 +167,7 @@ def _network_client_factory(): "routes", _network_client_factory, [ - (RoutesOperations.delete, None), + (RoutesOperations.delete, LongRunningOperation(L('Deleting route'), L('Route deleted'))), (RoutesOperations.get, 'Route'), (RoutesOperations.list, '[Route]'), ]) @@ -178,7 +178,7 @@ def _network_client_factory(): "security_rules", _network_client_factory, [ - (SecurityRulesOperations.delete, None), + (SecurityRulesOperations.delete, LongRunningOperation(L('Deleting security rule'), L('Security rule deleted'))), (SecurityRulesOperations.get, 'SecurityRule'), (SecurityRulesOperations.list, '[SecurityRule]'), ]) @@ -189,7 +189,7 @@ def _network_client_factory(): "subnets", _network_client_factory, [ - (SubnetsOperations.delete, None), + (SubnetsOperations.delete, LongRunningOperation(L('Deleting subnet'), L('Subnet deleted'))), (SubnetsOperations.get, 'Subnet'), (SubnetsOperations.list, '[Subnet]'), ]) @@ -209,7 +209,7 @@ def _network_client_factory(): "virtual_network_gateway_connections", _network_client_factory, [ - (VirtualNetworkGatewayConnectionsOperations.delete, None), + (VirtualNetworkGatewayConnectionsOperations.delete, LongRunningOperation(L('Deleting virtual network gateway connection'), L('Virtual network gateway connection deleted'))), (VirtualNetworkGatewayConnectionsOperations.get, 'VirtualNetworkGatewayConnection'), (VirtualNetworkGatewayConnectionsOperations.get_shared_key, 'ConnectionSharedKeyResult'), (VirtualNetworkGatewayConnectionsOperations.list, '[VirtualNetworkGatewayConnection]'), @@ -223,7 +223,7 @@ def _network_client_factory(): "virtual_network_gateways", _network_client_factory, [ - (VirtualNetworkGatewaysOperations.delete, None), + (VirtualNetworkGatewaysOperations.delete, LongRunningOperation(L('Deleting virtual network gateway'), L('Virtual network gateway deleted'))), (VirtualNetworkGatewaysOperations.get, 'VirtualNetworkGateway'), (VirtualNetworkGatewaysOperations.list, '[VirtualNetworkGateway]'), (VirtualNetworkGatewaysOperations.reset, 'VirtualNetworkGateway'), @@ -235,7 +235,7 @@ def _network_client_factory(): "virtual_networks", _network_client_factory, [ - (VirtualNetworksOperations.delete, None), + (VirtualNetworksOperations.delete, LongRunningOperation(L('Deleting virtual network'), L('Virtual network deleted'))), (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 index 28f2f077c42..7b9ca346485 100644 --- a/src/azure/cli/commands/vm.py +++ b/src/azure/cli/commands/vm.py @@ -44,7 +44,7 @@ def _compute_client_factory(): "virtual_machine_extensions", _compute_client_factory, [ - (VirtualMachineExtensionsOperations.delete, None), + (VirtualMachineExtensionsOperations.delete, LongRunningOperation(L('Deleting VM extension'), L('VM extension deleted'))), (VirtualMachineExtensionsOperations.get, 'VirtualMachineExtension'), ]) @@ -81,14 +81,14 @@ def _compute_client_factory(): "virtual_machines", _compute_client_factory, [ - (VirtualMachinesOperations.delete, None), - (VirtualMachinesOperations.deallocate, None), + (VirtualMachinesOperations.delete, LongRunningOperation(L('Deleting VM'), L('VM Deleted'))), + (VirtualMachinesOperations.deallocate, LongRunningOperation(L('Deallocating VM'), L('VM Deallocated'))), (VirtualMachinesOperations.generalize, None), (VirtualMachinesOperations.get, 'VirtualMachine'), (VirtualMachinesOperations.list, '[VirtualMachine]'), (VirtualMachinesOperations.list_all, '[VirtualMachine]'), (VirtualMachinesOperations.list_available_sizes, '[VirtualMachineSize]'), - (VirtualMachinesOperations.power_off, None), + (VirtualMachinesOperations.power_off, LongRunningOperation(L('Powering off VM'), L('VM powered off'))), (VirtualMachinesOperations.restart, LongRunningOperation(L('Restarting VM'), L('VM Restarted'))), (VirtualMachinesOperations.start, LongRunningOperation(L('Starting VM'), L('VM Started'))), ]) @@ -98,18 +98,18 @@ def _compute_client_factory(): "virtual_machine_scale_sets", _compute_client_factory, [ - (VirtualMachineScaleSetsOperations.deallocate, None), - (VirtualMachineScaleSetsOperations.delete, None), + (VirtualMachineScaleSetsOperations.deallocate, LongRunningOperation(L('Deallocating VM scale set'), L('VM scale set deallocated'))), + (VirtualMachineScaleSetsOperations.delete, LongRunningOperation(L('Deleting VM scale set'), L('VM scale set deleted'))), (VirtualMachineScaleSetsOperations.get, 'VirtualMachineScaleSet'), - (VirtualMachineScaleSetsOperations.delete_instances, None), + (VirtualMachineScaleSetsOperations.delete_instances, LongRunningOperation(L('Deleting VM scale set instances'), L('VM scale set instances deleted'))), (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), + (VirtualMachineScaleSetsOperations.power_off, LongRunningOperation(L('Powering off VM scale set'), L('VM scale set powered off'))), + (VirtualMachineScaleSetsOperations.restart, LongRunningOperation(L('Restarting VM scale set'), L('VM scale set restarted'))), + (VirtualMachineScaleSetsOperations.start, LongRunningOperation(L('Starting VM scale set'), L('VM scale set started'))), + (VirtualMachineScaleSetsOperations.update_instances, LongRunningOperation(L('Updating VM scale set instances'), L('VM scale set instances updated'))), ]) build_operation("vm", @@ -117,12 +117,12 @@ def _compute_client_factory(): "virtual_machine_scale_set_vms", _compute_client_factory, [ - (VirtualMachineScaleSetVMsOperations.deallocate, None), - (VirtualMachineScaleSetVMsOperations.delete, None), - (VirtualMachineScaleSetVMsOperations.get, None), + (VirtualMachineScaleSetVMsOperations.deallocate, LongRunningOperation(L('Deallocating VM scale set VMs'), L('VM scale set VMs deallocated'))), + (VirtualMachineScaleSetVMsOperations.delete, LongRunningOperation(L('Deleting VM scale set VMs'), L('VM scale set VMs deleted'))), + (VirtualMachineScaleSetVMsOperations.get, 'VirtualMachineScaleSetVM'), (VirtualMachineScaleSetVMsOperations.get_instance_view, 'VirtualMachineScaleSetVMInstanceView'), (VirtualMachineScaleSetVMsOperations.list, '[VirtualMachineScaleSetVM]'), - (VirtualMachineScaleSetVMsOperations.power_off, None), - (VirtualMachineScaleSetVMsOperations.restart, None), - (VirtualMachineScaleSetVMsOperations.start, None), + (VirtualMachineScaleSetVMsOperations.power_off, LongRunningOperation(L('Powering off VM scale set VMs'), L('VM scale set VMs powered off'))), + (VirtualMachineScaleSetVMsOperations.restart, LongRunningOperation(L('Restarting VM scale set VMs'), L('VM scale set VMs restarted'))), + (VirtualMachineScaleSetVMsOperations.start, LongRunningOperation(L('Starting VM scale set VMs'), L('VM scale set VMs started'))), ]) From ce903819a9a2d4c206739e0a274142efd25e958c Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Thu, 3 Mar 2016 07:53:36 -0800 Subject: [PATCH 10/19] reusing existing file-level variables and update auto-command to work for 2.7 --- src/azure/cli/commands/_auto_command.py | 3 ++- src/azure/cli/commands/network.py | 27 ++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/azure/cli/commands/_auto_command.py b/src/azure/cli/commands/_auto_command.py index 02a2722b190..821aa4d1fe6 100644 --- a/src/azure/cli/commands/_auto_command.py +++ b/src/azure/cli/commands/_auto_command.py @@ -23,7 +23,8 @@ def __call__(self, poller): try: while not poller.done(): if self.progress_file: - print('.', end='', flush=True, file=self.progress_file) + print('.', end='', file=self.progress_file) + self.progress_file.flush() time.sleep(self.poll_interval_ms / 1000.0) result = poller.result() succeeded = True diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index 1dd9a8b85da..ed6014866d6 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -19,12 +19,6 @@ VirtualNetworkGatewayConnectionsOperations, VirtualNetworkGatewaysOperations, VirtualNetworksOperations) -from azure.mgmt.network.models import (AddressSpace, - DhcpOptions, - # TODO: setting the IPConfiguration fails - #IPConfiguration, - Subnet, - VirtualNetwork) from ._command_creation import get_service_client from ..commands._auto_command import build_operation, LongRunningOperation @@ -254,22 +248,25 @@ def _network_client_factory(): @option('--resource-group -g ', L('the resource group name'), required=True) @option('--name -n ', L('the VNet name'), required=True) @option('--location -l ', L('the VNet location'), required=True) -@option('--address-space -a ', L('the VNet address-space in CIDR notation'), required=True) +@option('--address-space -a ', L('the VNet address-space in CIDR notation or multiple address-spaces, quoted and space-seperated'), required=True) @option('--dns-servers -d ', L('the VNet DNS servers')) def create_update_vnet(args, unexpected): #pylint: disable=unused-argument + from azure.mgmt.network.models import AddressSpace, DhcpOptions, VirtualNetwork + resource_group = args.get('resource-group') name = args.get('name') location = args.get('location') - address_space = AddressSpace(address_prefixes=[args.get('address-space')]) + address_space = AddressSpace(address_prefixes=args.get('address-space').split()) dhcp_options = DhcpOptions(dns_servers=args.get('dns-servers')) vnet_settings = VirtualNetwork(location=location, address_space=address_space, dhcp_options=dhcp_options) - smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) + op = LongRunningOperation('Creating virtual network', 'Virtual network created') + smc = _network_client_factory() poller = smc.virtual_networks.create_or_update(resource_group, name, vnet_settings) - return Serializer().serialize_data(poller.result(), "VirtualNetwork") + return Serializer().serialize_data(op(poller), 'VirtualNetwork') @command('network subnet create') @description(L('Create or update a virtual network (VNet) subnet')) @@ -283,6 +280,11 @@ def create_update_vnet(args, unexpected): #pylint: disable=unused-argument #@option('--ip-allocation-method -ipam ', L('the IP address allocation method')) #@option('--ip-public-address -ipa ', L('the public IP address')) def create_update_subnet(args, unexpected): #pylint: disable=unused-argument + from azure.mgmt.network.models import (Subnet, + # TODO: setting the IPConfiguration fails + #IPConfiguration, + ) + resource_group = args.get('resource-group') vnet = args.get('vnet') name = args.get('name') @@ -305,8 +307,9 @@ def create_update_subnet(args, unexpected): #pylint: disable=unused-argument # TODO: setting the IPConfiguration fails, will contact owning team #ip_configurations = [ip_configuration]) - smc = get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) + op = LongRunningOperation('Creating subnet', 'Subnet created') + smc = _network_client_factory() poller = smc.subnets.create_or_update(resource_group, vnet, name, subnet_settings) - return Serializer().serialize_data(poller.result(), "Subnet") + return Serializer().serialize_data(op(poller), 'Subnet') From 4384a0e0448f61b92c4c901e318dc21abb01f344 Mon Sep 17 00:00:00 2001 From: Burt Bielicki Date: Thu, 3 Mar 2016 10:20:37 -0800 Subject: [PATCH 11/19] converted dns_servers to array instead of string --- src/azure/cli/commands/network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index ed6014866d6..665d458bb3e 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -249,7 +249,7 @@ def _network_client_factory(): @option('--name -n ', L('the VNet name'), required=True) @option('--location -l ', L('the VNet location'), required=True) @option('--address-space -a ', L('the VNet address-space in CIDR notation or multiple address-spaces, quoted and space-seperated'), required=True) -@option('--dns-servers -d ', L('the VNet DNS servers')) +@option('--dns-servers -d ', L('the VNet DNS servers, quoted and space-seperated')) def create_update_vnet(args, unexpected): #pylint: disable=unused-argument from azure.mgmt.network.models import AddressSpace, DhcpOptions, VirtualNetwork @@ -257,7 +257,7 @@ def create_update_vnet(args, unexpected): #pylint: disable=unused-argument name = args.get('name') location = args.get('location') address_space = AddressSpace(address_prefixes=args.get('address-space').split()) - dhcp_options = DhcpOptions(dns_servers=args.get('dns-servers')) + dhcp_options = DhcpOptions(dns_servers=args.get('dns-servers').split()) vnet_settings = VirtualNetwork(location=location, address_space=address_space, From 0c6c898e48c115ee812db31be78b053b7d61d006 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Wed, 2 Mar 2016 14:46:47 -0800 Subject: [PATCH 12/19] Initial bash scripts for tab completion --- az.completion.sh | 13 ++++++++++ src/azure/cli/_argparse.py | 7 +++--- src/azure/cli/tests/test_argparse.py | 37 +++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 az.completion.sh diff --git a/az.completion.sh b/az.completion.sh new file mode 100644 index 00000000000..654b52eb0d2 --- /dev/null +++ b/az.completion.sh @@ -0,0 +1,13 @@ +if type compdef &>/dev/null; then + #ZSH + _az_complete() { + compadd -- `"${COMP_WORDS[0]}" --complete "${words[@]:1}"` + } + compdef _az_complete az +elif type complete &>/dev/null; then + #BASH + _az_complete() { + COMPREPLY=( $(compgen -W '$("${COMP_WORDS[0]}" --complete "${COMP_WORDS[@]:1}")' -- "${COMP_WORDS[COMP_CWORD]}") ) + } + complete -F _az_complete az +fi diff --git a/src/azure/cli/_argparse.py b/src/azure/cli/_argparse.py index fc7ae204ed6..081e35ebbf6 100644 --- a/src/azure/cli/_argparse.py +++ b/src/azure/cli/_argparse.py @@ -264,15 +264,16 @@ def _display_usage(self, nouns, noun_map, out=sys.stdout): out.flush() logger.debug('Expected documentation at %s', doc_file) - def _display_completions(self, noun_map, arguments, out=sys.stdout): # pylint: disable=no-self-use - arguments.remove('--complete') + def _display_completions(self, noun_map, arguments, out=sys.stdout): + for a in self.complete_args: + arguments.remove(a) command_candidates = set([k for k in noun_map if not k.startswith('$')]) if command_candidates and not arguments[-1].startswith('-'): command_candidates = set([c for c in command_candidates if c.startswith(arguments[-1])]) kwargs = noun_map.get('$kwargs') or [] - args_candidates = set('--' + a for a in kwargs if a) + args_candidates = set(('--' if len(a) > 1 else '-') + a for a in kwargs) if arguments[-1].startswith('-'): # TODO: We don't have enough metadata about the command to do parameter value # completion (yet). This should only apply to value arguments, not flag arguments diff --git a/src/azure/cli/tests/test_argparse.py b/src/azure/cli/tests/test_argparse.py index 1ba3540800a..457770dbbe6 100644 --- a/src/azure/cli/tests/test_argparse.py +++ b/src/azure/cli/tests/test_argparse.py @@ -1,9 +1,17 @@ +try: + # on Python2, we like to use the module "StringIO" rather "io" so to + # avoid "print" errors like: TypeError: string argument expected, got 'str' + from StringIO import StringIO +except ImportError: + # Python 3 + from io import StringIO + import unittest from azure.cli._argparse import ArgumentParser, IncorrectUsageError from azure.cli._logging import logger import logging - +import azure.cli._util as util class Test_argparse(unittest.TestCase): @classmethod @@ -94,6 +102,33 @@ def test_required_args(self): self.assertIsNone(p.execute('n1 -b x'.split())) + def test_args_completion(self): + p = ArgumentParser('test') + p.add_command(lambda a, b: (a, b), 'n1', args=[('--arg -a', '', True), ('-b ', '', False)]) + io = StringIO() + + p.execute('n1 - --complete'.split(), + show_usage=False, + show_completions=True, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, '--arg\n-a\n-b\n') + + io = StringIO() + p.execute('n1 --a --complete'.split(), + show_usage=False, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, '--arg\n') + + io = StringIO() + p.execute('n --a --complete'.split(), + show_usage=False, + show_completions=True, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, 'n1\n') + if __name__ == '__main__': unittest.main() From 93509e69aab4cbfafe4197bfd312be61879fa370 Mon Sep 17 00:00:00 2001 From: Johan Stenberg Date: Thu, 3 Mar 2016 15:10:15 -0800 Subject: [PATCH 13/19] Remove accidental double-space in description --- src/azure/cli/commands/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index 99212cdc407..72e2ee39115 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -36,7 +36,7 @@ def _network_client_factory(): (ApplicationGatewaysOperations.get, 'ApplicationGateway'), (ApplicationGatewaysOperations.list, '[ApplicationGateway]'), (ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'), - (ApplicationGatewaysOperations.start, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), + (ApplicationGatewaysOperations.start, LongRunningOperation(L('Starting application gateway'), L('Application gateway started'))), (ApplicationGatewaysOperations.stop, LongRunningOperation(L('Stopping application gateway'), L('Application gateway stopped'))), ]) From 6d0e0e5387dbbb393133989ca4214bd1f6efd622 Mon Sep 17 00:00:00 2001 From: Derek Bekoe Date: Thu, 3 Mar 2016 13:03:29 -0800 Subject: [PATCH 14/19] List format with user friendly formatting --- src/azure/cli/_output.py | 64 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/azure/cli/_output.py b/src/azure/cli/_output.py index f5dc596f7e0..2b647a561e4 100644 --- a/src/azure/cli/_output.py +++ b/src/azure/cli/_output.py @@ -2,6 +2,7 @@ import sys import json +import re try: # Python 3 @@ -40,15 +41,76 @@ def format_text(obj): except TypeError: return '' +def format_list(obj): + lo = ListOutput() + return lo.dump(obj) + class OutputProducer(object): #pylint: disable=too-few-public-methods - def __init__(self, formatter=format_json, file=sys.stdout): #pylint: disable=redefined-builtin + def __init__(self, formatter=format_list, file=sys.stdout): #pylint: disable=redefined-builtin self.formatter = formatter self.file = file def out(self, obj): print(self.formatter(obj), file=self.file) +class ListOutput(object): #pylint: disable=too-few-public-methods + + def __init__(self): + self._formatted_keys_cache = {} + + @staticmethod + def _get_max_key_len(keys): + return len(max(keys, key=len)) if keys else 0 + + @staticmethod + def _sort_key_func(key, item): + # we want dictionaries to be last so use ASCII char 126 ~ to + # prefix dictionary key names. + return '~'+key if isinstance(item[key], dict) else key + + def _get_formatted_key(self, key): + def _format_key(key): + words = [word for word in re.split('([A-Z][^A-Z]*)', key) if word] + return ' '.join(words).title() + + try: + return self._formatted_keys_cache[key] + except KeyError: + self._formatted_keys_cache[key] = _format_key(key) + return self._formatted_keys_cache[key] + + def _dump_object(self, io, item, indent): + # get the formatted keys for this item + # skip dicts because those will be handled recursively later. + item_f_keys = {k: self._get_formatted_key(k) for k in item if not isinstance(item[k], dict)} + key_width = ListOutput._get_max_key_len(item_f_keys.values()) + for key in sorted(item, key=lambda x: ListOutput._sort_key_func(x, item)): + if isinstance(item[key], dict): + # complex object + io.write('\n') + io.write('\t' * (indent+1)) + io.write(self._get_formatted_key(key).upper()) + io.write('\n') + if item[key]: + self._dump_object(io, item[key], indent+1) + else: + io.write('\t' * (indent+1)) + io.write('None') + io.write('\n') + else: + # non-complex so write it + io.write('\t' * indent) + io.write('%s : %s' % (self._get_formatted_key(key).ljust(key_width), item[key])) + io.write('\n') + + def dump(self, data): + with StringIO() as io: + for item in sorted(data, key=lambda x: sorted(x.keys())): + self._dump_object(io, item, 0) + io.write('\n') + return io.getvalue() + class TableOutput(object): def __init__(self): self._rows = [{}] From d1d4299d87509df2f34f68dfb48c849fb56b609d Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Thu, 3 Mar 2016 16:48:54 -0800 Subject: [PATCH 15/19] create docker file based on python3 and pip3 --- Dockerfile | 38 ++++++++++++++------------------------ Dockerfile-2.7 | 33 +++++++++++++++++++++++++++++++++ az | 3 +-- 3 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 Dockerfile-2.7 diff --git a/Dockerfile b/Dockerfile index 204659f5c05..277fba9bead 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,26 @@ -FROM ubuntu:14.04 - -RUN rm /bin/sh && ln -s /bin/bash /bin/sh +FROM ubuntu:15.10 RUN apt-get update -qq && \ apt-get install -qqy --no-install-recommends\ - build-essential \ - curl \ - ca-certificates \ - git \ - python-pip \ - libffi-dev \ - libssl-dev \ - python-dev \ + python3-pip \ vim \ - nano \ jq && \ - rm -rf /var/lib/apt/lists/* && \ - pip install azure==2.0.0a1 && \ - pip install --upgrade requests && \ - pip install cryptography && \ - pip install pyopenssl ndg-httpsclient pyasn1 + rm -rf /var/lib/apt/lists/* + +RUN pip3 install azure==2.0.0a1 -ENV AZURECLITEMP /tmp/azure-cli +ENV AZURECLITEMP /opt/azure-cli ENV PYTHONPATH $PYTHONPATH:$AZURECLITEMP/src ENV PATH $PATH:$AZURECLITEMP RUN mkdir -p $AZURECLITEMP -ADD src $AZURECLITEMP/src +COPY src $AZURECLITEMP/src +COPY az.completion.sh $AZURECLITEMP/ +COPY az $AZURECLITEMP/ -RUN echo '#!/bin/bash'>$AZURECLITEMP/az && \ - echo 'python -m azure.cli "$@"'>>$AZURECLITEMP/az && \ - chmod +x $AZURECLITEMP/az && \ - az +RUN chmod +x $AZURECLITEMP/az +RUN ln /usr/bin/python3 /usr/bin/python +RUN echo "source $AZURECLITEMP/az.completion.sh" >> ~/.bashrc +RUN az -ENV EDITOR vim +ENV EDITOR vim \ No newline at end of file diff --git a/Dockerfile-2.7 b/Dockerfile-2.7 new file mode 100644 index 00000000000..091768d2973 --- /dev/null +++ b/Dockerfile-2.7 @@ -0,0 +1,33 @@ +FROM ubuntu:14.04 + +RUN apt-get update -qq && \ + apt-get install -qqy --no-install-recommends\ + build-essential \ + curl \ + ca-certificates \ + python-pip \ + libffi-dev \ + libssl-dev \ + python-dev \ + vim \ + jq && \ + rm -rf /var/lib/apt/lists/* && \ + pip install azure==2.0.0a1 && \ + pip install --upgrade requests && \ + pip install cryptography && \ + pip install pyopenssl ndg-httpsclient pyasn1 + +ENV AZURECLITEMP /opt/azure-cli +ENV PYTHONPATH $PYTHONPATH:$AZURECLITEMP/src +ENV PATH $PATH:$AZURECLITEMP + +RUN mkdir -p $AZURECLITEMP +COPY src $AZURECLITEMP/src +COPY az.completion.sh $AZURECLITEMP/ +COPY az $AZURECLITEMP/ + +RUN chmod +x $AZURECLITEMP/az +RUN echo "source $AZURECLITEMP/az.completion.sh" >> ~/.bashrc +RUN az + +ENV EDITOR vim \ No newline at end of file diff --git a/az b/az index c4b5a8d6d7b..e7b0cefdac4 100644 --- a/az +++ b/az @@ -10,6 +10,5 @@ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" export PYTHONPATH="${DIR}/src:${PYTHONPATH}" -python -m azure.cli "$@" - +python -m azure.cli "$@" From e1d27cae2c1493bd6cf1f50f2fcaf9a948424f92 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Fri, 4 Mar 2016 14:16:08 -0800 Subject: [PATCH 16/19] use azure sdk rc1 --- Dockerfile | 2 +- Dockerfile-2.7 | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 277fba9bead..20df86a2157 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update -qq && \ jq && \ rm -rf /var/lib/apt/lists/* -RUN pip3 install azure==2.0.0a1 +RUN pip3 install azure==2.0.0rc1 ENV AZURECLITEMP /opt/azure-cli ENV PYTHONPATH $PYTHONPATH:$AZURECLITEMP/src diff --git a/Dockerfile-2.7 b/Dockerfile-2.7 index 091768d2973..8ceae9011ce 100644 --- a/Dockerfile-2.7 +++ b/Dockerfile-2.7 @@ -12,7 +12,7 @@ RUN apt-get update -qq && \ vim \ jq && \ rm -rf /var/lib/apt/lists/* && \ - pip install azure==2.0.0a1 && \ + pip install azure==2.0.0rc1 && \ pip install --upgrade requests && \ pip install cryptography && \ pip install pyopenssl ndg-httpsclient pyasn1 diff --git a/requirements.txt b/requirements.txt index f59fa6d46c6..4a832dd5384 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -azure==2.0.0a1 +azure==2.0.0rc1 mock==1.3.0 pylint==1.5.4 From 00c40437469c4d3dff5a8271199d142fbbefddbc Mon Sep 17 00:00:00 2001 From: Derek Bekoe Date: Thu, 3 Mar 2016 18:04:41 -0800 Subject: [PATCH 17/19] Support lists and well as dicts --- Also, fix StringIO issue with Python 2 vs. 3 --- src/azure/cli/_output.py | 146 +++++++++++++++++------------ src/azure/cli/tests/test_output.py | 67 ++++++++++++- 2 files changed, 153 insertions(+), 60 deletions(-) diff --git a/src/azure/cli/_output.py b/src/azure/cli/_output.py index 2b647a561e4..0faf8c10cb3 100644 --- a/src/azure/cli/_output.py +++ b/src/azure/cli/_output.py @@ -4,12 +4,7 @@ import json import re -try: - # Python 3 - from io import StringIO -except ImportError: - # Python 2 - from StringIO import StringIO #pylint: disable=import-error +from six import StringIO class OutputFormatException(Exception): pass @@ -42,8 +37,9 @@ def format_text(obj): return '' def format_list(obj): + obj_list = obj if isinstance(obj, list) else [obj] lo = ListOutput() - return lo.dump(obj) + return lo.dump(obj_list) class OutputProducer(object): #pylint: disable=too-few-public-methods @@ -56,6 +52,9 @@ def out(self, obj): class ListOutput(object): #pylint: disable=too-few-public-methods + # Match the capital letters in a camel case string + FORMAT_KEYS_PATTERN = re.compile('([A-Z][^A-Z]*)') + def __init__(self): self._formatted_keys_cache = {} @@ -65,13 +64,18 @@ def _get_max_key_len(keys): @staticmethod def _sort_key_func(key, item): - # we want dictionaries to be last so use ASCII char 126 ~ to - # prefix dictionary key names. - return '~'+key if isinstance(item[key], dict) else key + # We want dictionaries to be last so use ASCII char 126 ~ to + # prefix dictionary and list key names. + if isinstance(item[key], dict): + return '~~'+key + elif isinstance(item[key], list): + return '~'+key + else: + return key def _get_formatted_key(self, key): def _format_key(key): - words = [word for word in re.split('([A-Z][^A-Z]*)', key) if word] + words = [word for word in re.split(ListOutput.FORMAT_KEYS_PATTERN, key) if word] return ' '.join(words).title() try: @@ -80,36 +84,56 @@ def _format_key(key): self._formatted_keys_cache[key] = _format_key(key) return self._formatted_keys_cache[key] - def _dump_object(self, io, item, indent): - # get the formatted keys for this item - # skip dicts because those will be handled recursively later. - item_f_keys = {k: self._get_formatted_key(k) for k in item if not isinstance(item[k], dict)} - key_width = ListOutput._get_max_key_len(item_f_keys.values()) - for key in sorted(item, key=lambda x: ListOutput._sort_key_func(x, item)): - if isinstance(item[key], dict): - # complex object - io.write('\n') - io.write('\t' * (indent+1)) - io.write(self._get_formatted_key(key).upper()) - io.write('\n') - if item[key]: - self._dump_object(io, item[key], indent+1) - else: - io.write('\t' * (indent+1)) - io.write('None') + @staticmethod + def _dump_line(io, line, indent): + io.write(' ' * indent) + io.write(line) + io.write('\n') + + def _dump_object(self, io, obj, indent): + if isinstance(obj, list): + for array_item in obj: + self._dump_object(io, array_item, indent+1) + elif isinstance(obj, dict): + # Get the formatted keys for this item + # Skip dicts/lists because those will be handled recursively later. + # We use this object to calc key width and don't want to dicts/lists in this. + obj_fk = {k: self._get_formatted_key(k) + for k in obj if not isinstance(obj[k], dict) and not isinstance(obj[k], list)} + key_width = ListOutput._get_max_key_len(obj_fk.values()) + for key in sorted(obj, key=lambda x: ListOutput._sort_key_func(x, obj)): + if isinstance(obj[key], dict): + # complex object + io.write('\n') + ListOutput._dump_line(io, self._get_formatted_key(key).upper(), indent+1) + if obj[key]: + self._dump_object(io, obj[key], indent+1) + else: + ListOutput._dump_line(io, 'None', indent+1) + elif isinstance(obj[key], list): + # list object io.write('\n') - else: - # non-complex so write it - io.write('\t' * indent) - io.write('%s : %s' % (self._get_formatted_key(key).ljust(key_width), item[key])) - io.write('\n') + ListOutput._dump_line(io, self._get_formatted_key(key).upper(), indent+1) + if obj[key]: + for array_item in obj[key]: + self._dump_object(io, array_item, indent+1) + else: + ListOutput._dump_line(io, 'None', indent+1) + else: + # non-complex so write it + line = '%s : %s' % (self._get_formatted_key(key).ljust(key_width), obj[key]) + ListOutput._dump_line(io, line, indent) + else: + ListOutput._dump_line(io, obj, indent) def dump(self, data): - with StringIO() as io: - for item in sorted(data, key=lambda x: sorted(x.keys())): - self._dump_object(io, item, 0) - io.write('\n') - return io.getvalue() + io = StringIO() + for obj in data: + self._dump_object(io, obj, 0) + io.write('\n') + result = io.getvalue() + io.close() + return result class TableOutput(object): def __init__(self): @@ -121,16 +145,18 @@ def dump(self): if len(self._rows) == 1: return - with StringIO() as io: - cols = [(c, self._columns[c]) for c in self._column_order] - io.write(' | '.join(c.center(w) for c, w in cols)) - io.write('\n') - io.write('-|-'.join('-' * w for c, w in cols)) + io = StringIO() + cols = [(c, self._columns[c]) for c in self._column_order] + io.write(' | '.join(c.center(w) for c, w in cols)) + io.write('\n') + io.write('-|-'.join('-' * w for c, w in cols)) + io.write('\n') + for r in self._rows[:-1]: + io.write(' | '.join(r[c].ljust(w) for c, w in cols)) io.write('\n') - for r in self._rows[:-1]: - io.write(' | '.join(r[c].ljust(w) for c, w in cols)) - io.write('\n') - return io.getvalue() + result = io.getvalue() + io.close() + return result @property def any_rows(self): @@ -161,17 +187,19 @@ def add(self, identifier, value): self.identifiers[identifier] = [value] def dump(self): - with StringIO() as io: - for identifier in sorted(self.identifiers): - io.write(identifier.upper()) + io = StringIO() + for identifier in sorted(self.identifiers): + io.write(identifier.upper()) + io.write('\t') + for col in self.identifiers[identifier]: + if isinstance(col, str): + io.write(col) + else: + # TODO: Need to handle complex objects + io.write("null") io.write('\t') - for col in self.identifiers[identifier]: - if isinstance(col, str): - io.write(col) - else: - # TODO: Need to handle complex objects - io.write("null") - io.write('\t') - io.write('\n') - return io.getvalue() + io.write('\n') + result = io.getvalue() + io.close() + return result diff --git a/src/azure/cli/tests/test_output.py b/src/azure/cli/tests/test_output.py index 14ab85cb96c..343bbda728d 100644 --- a/src/azure/cli/tests/test_output.py +++ b/src/azure/cli/tests/test_output.py @@ -9,7 +9,7 @@ # Python 2 from StringIO import StringIO -from azure.cli._output import OutputProducer, OutputFormatException, format_json, format_table, format_text +from azure.cli._output import OutputProducer, OutputFormatException, format_json, format_table, format_list, format_text import azure.cli._util as util class TestOutput(unittest.TestCase): @@ -51,6 +51,71 @@ def test_out_table_valid(self): -------|--------- True | 0b1f6472 +""")) + + def test_out_list_valid(self): + """ + """ + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out({'active': True, 'id': '0b1f6472'}) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""Active : True +Id : 0b1f6472 + + +""")) + + def test_out_list_valid_array_complex(self): + """ + """ + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out([{'active': True, 'id': '783yesdf'}, {'active': False, 'id': '3hjnme32'}, {'active': False, 'id': '23hiujbs'}]) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""Active : True +Id : 783yesdf + +Active : False +Id : 3hjnme32 + +Active : False +Id : 23hiujbs + + +""")) + + def test_out_list_valid_str_array(self): + """ + """ + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out(['location', 'id', 'host', 'server']) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""location + +id + +host + +server + + +""")) + + def test_out_list_valid_complex_array(self): + """ + """ + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out({'active': True, 'id': '0b1f6472', 'myarray': ['1', '2', '3', '4']}) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""Active : True +Id : 0b1f6472 + + MYARRAY + 1 + 2 + 3 + 4 + + """)) if __name__ == '__main__': From aa560e22da517878ed7070ac8ba2718f6f1923c9 Mon Sep 17 00:00:00 2001 From: Derek Bekoe Date: Fri, 4 Mar 2016 17:10:06 -0800 Subject: [PATCH 18/19] Simplify code, add more tests --- src/azure/cli/_output.py | 21 +++-------- src/azure/cli/tests/test_output.py | 60 ++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/azure/cli/_output.py b/src/azure/cli/_output.py index 0faf8c10cb3..e92fe3ec680 100644 --- a/src/azure/cli/_output.py +++ b/src/azure/cli/_output.py @@ -93,7 +93,7 @@ def _dump_line(io, line, indent): def _dump_object(self, io, obj, indent): if isinstance(obj, list): for array_item in obj: - self._dump_object(io, array_item, indent+1) + self._dump_object(io, array_item, indent) elif isinstance(obj, dict): # Get the formatted keys for this item # Skip dicts/lists because those will be handled recursively later. @@ -102,26 +102,15 @@ def _dump_object(self, io, obj, indent): for k in obj if not isinstance(obj[k], dict) and not isinstance(obj[k], list)} key_width = ListOutput._get_max_key_len(obj_fk.values()) for key in sorted(obj, key=lambda x: ListOutput._sort_key_func(x, obj)): - if isinstance(obj[key], dict): + if isinstance(obj[key], dict) or isinstance(obj[key], list): # complex object io.write('\n') ListOutput._dump_line(io, self._get_formatted_key(key).upper(), indent+1) - if obj[key]: - self._dump_object(io, obj[key], indent+1) - else: - ListOutput._dump_line(io, 'None', indent+1) - elif isinstance(obj[key], list): - # list object - io.write('\n') - ListOutput._dump_line(io, self._get_formatted_key(key).upper(), indent+1) - if obj[key]: - for array_item in obj[key]: - self._dump_object(io, array_item, indent+1) - else: - ListOutput._dump_line(io, 'None', indent+1) + self._dump_object(io, obj[key] if obj[key] else 'None', indent+1) else: # non-complex so write it - line = '%s : %s' % (self._get_formatted_key(key).ljust(key_width), obj[key]) + line = '%s : %s' % (self._get_formatted_key(key).ljust(key_width), + 'None' if obj[key] is None else obj[key]) ListOutput._dump_line(io, line, indent) else: ListOutput._dump_line(io, obj, indent) diff --git a/src/azure/cli/tests/test_output.py b/src/azure/cli/tests/test_output.py index 343bbda728d..c2c62f32357 100644 --- a/src/azure/cli/tests/test_output.py +++ b/src/azure/cli/tests/test_output.py @@ -9,7 +9,8 @@ # Python 2 from StringIO import StringIO -from azure.cli._output import OutputProducer, OutputFormatException, format_json, format_table, format_list, format_text +from azure.cli._output import (OutputProducer, OutputFormatException, format_json, format_table, format_list, format_text, + ListOutput) import azure.cli._util as util class TestOutput(unittest.TestCase): @@ -42,8 +43,6 @@ def test_out_json_valid(self): """)) def test_out_table_valid(self): - """ - """ output_producer = OutputProducer(formatter=format_table, file=self.io) output_producer.out({'active': True, 'id': '0b1f6472'}) self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( @@ -54,8 +53,6 @@ def test_out_table_valid(self): """)) def test_out_list_valid(self): - """ - """ output_producer = OutputProducer(formatter=format_list, file=self.io) output_producer.out({'active': True, 'id': '0b1f6472'}) self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( @@ -63,11 +60,32 @@ def test_out_list_valid(self): Id : 0b1f6472 +""")) + + def test_out_list_valid_none_val(self): + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out({'active': None, 'id': '0b1f6472'}) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""Active : None +Id : 0b1f6472 + + +""")) + + def test_out_list_valid_empty_array(self): + output_producer = OutputProducer(formatter=format_list, file=self.io) + output_producer.out({'active': None, 'id': '0b1f6472', 'hosts': []}) + self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( +"""Active : None +Id : 0b1f6472 + + HOSTS + None + + """)) def test_out_list_valid_array_complex(self): - """ - """ output_producer = OutputProducer(formatter=format_list, file=self.io) output_producer.out([{'active': True, 'id': '783yesdf'}, {'active': False, 'id': '3hjnme32'}, {'active': False, 'id': '23hiujbs'}]) self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( @@ -84,8 +102,6 @@ def test_out_list_valid_array_complex(self): """)) def test_out_list_valid_str_array(self): - """ - """ output_producer = OutputProducer(formatter=format_list, file=self.io) output_producer.out(['location', 'id', 'host', 'server']) self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( @@ -101,8 +117,6 @@ def test_out_list_valid_str_array(self): """)) def test_out_list_valid_complex_array(self): - """ - """ output_producer = OutputProducer(formatter=format_list, file=self.io) output_producer.out({'active': True, 'id': '0b1f6472', 'myarray': ['1', '2', '3', '4']}) self.assertEqual(util.normalize_newlines(self.io.getvalue()), util.normalize_newlines( @@ -118,5 +132,29 @@ def test_out_list_valid_complex_array(self): """)) + def test_out_list_format_key_simple(self): + lo = ListOutput() + self.assertEqual(lo._formatted_keys_cache, {}) + lo._get_formatted_key('locationId') + self.assertEqual(lo._formatted_keys_cache, {'locationId': 'Location Id'}) + + def test_out_list_format_key_single(self): + lo = ListOutput() + self.assertEqual(lo._formatted_keys_cache, {}) + lo._get_formatted_key('location') + self.assertEqual(lo._formatted_keys_cache, {'location': 'Location'}) + + def test_out_list_format_key_multiple_caps(self): + lo = ListOutput() + self.assertEqual(lo._formatted_keys_cache, {}) + lo._get_formatted_key('fooIDS') + self.assertEqual(lo._formatted_keys_cache, {'fooIDS': 'Foo I D S'}) + + def test_out_list_format_key_multiple_words(self): + lo = ListOutput() + self.assertEqual(lo._formatted_keys_cache, {}) + lo._get_formatted_key('locationIdState') + self.assertEqual(lo._formatted_keys_cache, {'locationIdState': 'Location Id State'}) + if __name__ == '__main__': unittest.main() From 9aeaa60dec21fd3221e2348d96ecc3c3f34a57dc Mon Sep 17 00:00:00 2001 From: Derek Bekoe Date: Mon, 7 Mar 2016 09:56:03 -0800 Subject: [PATCH 19/19] Allow user to specify an output format [114821361] --- Argument Parser returns an object containing the result and the output format specified Add tests for command output format specifying --- src/azure/cli/_argparse.py | 27 +++++++++--- src/azure/cli/_output.py | 10 +++++ src/azure/cli/main.py | 7 +-- src/azure/cli/tests/test_argparse.py | 58 ++++++++++++++++++++----- src/azure/cli/tests/test_autocommand.py | 4 +- 5 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/azure/cli/_argparse.py b/src/azure/cli/_argparse.py index 081e35ebbf6..ab825f2045b 100644 --- a/src/azure/cli/_argparse.py +++ b/src/azure/cli/_argparse.py @@ -3,6 +3,7 @@ from ._locale import L, get_file as locale_get_file from ._logging import logger +from ._output import OutputProducer # Named arguments are prefixed with one of these strings ARG_PREFIXES = sorted(('-', '--', '/'), key=len, reverse=True) @@ -57,6 +58,10 @@ def _index(string, char, default=sys.maxsize): except ValueError: return default +class ArgumentParserResult(object): #pylint: disable=too-few-public-methods + def __init__(self, result, output_format=None): + self.result = result + self.output_format = output_format class ArgumentParser(object): def __init__(self, prog): @@ -125,6 +130,7 @@ def add_command(self, #pylint: disable=too-many-branches #pylint: disable=too-many-statements #pylint: disable=too-many-locals + #pylint: disable=too-many-return-statements def execute(self, args, show_usage=False, @@ -177,9 +183,9 @@ def not_global(a): show_usage = True if show_completions: - return self._display_completions(m, args, out) + return ArgumentParserResult(self._display_completions(m, args, out)) if show_usage: - return self._display_usage(nouns, m, out) + return ArgumentParserResult(self._display_usage(nouns, m, out)) parsed = Arguments() others = Arguments() @@ -199,7 +205,7 @@ def not_global(a): if value is not None: print(L("argument '{0}' does not take a value").format(key_n), file=out) - return self._display_usage(nouns, m, out) + return ArgumentParserResult(self._display_usage(nouns, m, out)) parsed.add_from_dotted(target_value[0], True) else: # Arg with a value @@ -217,15 +223,24 @@ def not_global(a): parsed[a] except KeyError: print(L("Missing required argument {}".format(a))) - return self._display_usage(nouns, m, out) + return ArgumentParserResult(self._display_usage(nouns, m, out)) + + output_format = None + if others and 'output' in others: + if others['output'] in OutputProducer.format_dict: + output_format = others['output'] + del others['output'] + else: + print(L("Invalid output format '{}' specified".format(others['output']))) + return ArgumentParserResult(self._display_usage(nouns, m, out)) old_stdout = sys.stdout try: sys.stdout = out - return handler(parsed, others) + return ArgumentParserResult(handler(parsed, others), output_format) except IncorrectUsageError as ex: print(str(ex), file=out) - return self._display_usage(nouns, m, out) + return ArgumentParserResult(self._display_usage(nouns, m, out)) finally: sys.stdout = old_stdout diff --git a/src/azure/cli/_output.py b/src/azure/cli/_output.py index f5dc596f7e0..511fc42b2c5 100644 --- a/src/azure/cli/_output.py +++ b/src/azure/cli/_output.py @@ -42,6 +42,12 @@ def format_text(obj): class OutputProducer(object): #pylint: disable=too-few-public-methods + format_dict = { + 'json': format_json, + 'table': format_table, + 'text': format_text + } + def __init__(self, formatter=format_json, file=sys.stdout): #pylint: disable=redefined-builtin self.formatter = formatter self.file = file @@ -49,6 +55,10 @@ def __init__(self, formatter=format_json, file=sys.stdout): #pylint: disable=red def out(self, obj): print(self.formatter(obj), file=self.file) + @staticmethod + def get_formatter(format_type): + return OutputProducer.format_dict.get(format_type, format_json) + class TableOutput(object): def __init__(self): self._rows = [{}] diff --git a/src/azure/cli/main.py b/src/azure/cli/main.py index 7c822cca712..b1fc8c455af 100644 --- a/src/azure/cli/main.py +++ b/src/azure/cli/main.py @@ -38,11 +38,12 @@ def main(args): commands.add_to_parser(parser) try: - result = parser.execute(args) + cmd_res = parser.execute(args) # Commands can return a dictionary/list of results # If they do, we print the results. - if result: - OutputProducer().out(result) + if cmd_res.result: + formatter = OutputProducer.get_formatter(cmd_res.output_format) + OutputProducer(formatter=formatter).out(cmd_res.result) except RuntimeError as ex: logger.error(ex.args[0]) return ex.args[1] if len(ex.args) >= 2 else -1 diff --git a/src/azure/cli/tests/test_argparse.py b/src/azure/cli/tests/test_argparse.py index 457770dbbe6..d8b7efd702f 100644 --- a/src/azure/cli/tests/test_argparse.py +++ b/src/azure/cli/tests/test_argparse.py @@ -46,31 +46,38 @@ def test_args(self): p = ArgumentParser('test') p.add_command(lambda a, b: (a, b), 'n1', args=[('--arg -a', '', False), ('-b ', '', False)]) - res, other = p.execute('n1 -a x'.split()) + cmd_res = p.execute('n1 -a x'.split()) + res, other = cmd_res.result self.assertTrue(res.arg) self.assertSequenceEqual(res.positional, ['x']) # Should recognize args with alternate prefix - res, other = p.execute('n1 /a'.split()) + cmd_res = p.execute('n1 /a'.split()) + res, other = cmd_res.result self.assertTrue(res.arg) - res, other = p.execute('n1 /arg'.split()) + cmd_res = p.execute('n1 /arg'.split()) + res, other = cmd_res.result self.assertTrue(res.arg) # Should not recognize "------a" - res, other = p.execute('n1 ------a'.split()) + cmd_res = p.execute('n1 ------a'.split()) + res, other = cmd_res.result self.assertNotIn('arg', res) # First two '--' match, so '----a' is added to dict self.assertIn('----a', other) - res = p.execute('n1 -a:x'.split()) + cmd_res = p.execute('n1 -a:x'.split()) + res = cmd_res.result self.assertIsNone(res) - res, other = p.execute('n1 -b -a x'.split()) + cmd_res = p.execute('n1 -b -a x'.split()) + res, other = cmd_res.result self.assertEqual(res.b, '-a') self.assertSequenceEqual(res.positional, ['x']) self.assertRaises(IncorrectUsageError, lambda: res.arg) - res, other = p.execute('n1 -b:-a x'.split()) + cmd_res = p.execute('n1 -b:-a x'.split()) + res, other = cmd_res.result self.assertEqual(res.b, '-a') self.assertSequenceEqual(res.positional, ['x']) self.assertRaises(IncorrectUsageError, lambda: res.arg) @@ -79,15 +86,18 @@ def test_unexpected_args(self): p = ArgumentParser('test') p.add_command(lambda a, b: (a, b), 'n1', args=[('-a', '', False)]) - res, other = p.execute('n1 -b=2'.split()) + cmd_res = p.execute('n1 -b=2'.split()) + res, other = cmd_res.result self.assertFalse(res) self.assertEqual('2', other.b) - res, other = p.execute('n1 -b.c.d=2'.split()) + cmd_res = p.execute('n1 -b.c.d=2'.split()) + res, other = cmd_res.result self.assertFalse(res) self.assertEqual('2', other.b.c.d) - res, other = p.execute('n1 -b.c.d 2 -b.c.e:3'.split()) + cmd_res = p.execute('n1 -b.c.d 2 -b.c.e:3'.split()) + res, other = cmd_res.result self.assertFalse(res) self.assertEqual('2', other.b.c.d) self.assertEqual('3', other.b.c.e) @@ -96,11 +106,12 @@ def test_required_args(self): p = ArgumentParser('test') p.add_command(lambda a, b: (a, b), 'n1', args=[('--arg -a', '', True), ('-b ', '', False)]) - res, other = p.execute('n1 -a x'.split()) + cmd_res = p.execute('n1 -a x'.split()) + res, other = cmd_res.result self.assertTrue(res.arg) self.assertSequenceEqual(res.positional, ['x']) - self.assertIsNone(p.execute('n1 -b x'.split())) + self.assertIsNone(p.execute('n1 -b x'.split()).result) def test_args_completion(self): p = ArgumentParser('test') @@ -129,6 +140,29 @@ def test_args_completion(self): candidates = util.normalize_newlines(io.getvalue()) self.assertEqual(candidates, 'n1\n') + def test_specify_output_format(self): + p = ArgumentParser('test') + p.add_command(lambda a, b: (a, b), 'n1', args=[('--arg -a', '', True), ('-b ', '', False)]) + + cmd_res = p.execute('n1 -a x'.split()) + self.assertEqual(cmd_res.output_format, None) + + cmd_res = p.execute('n1 -a x --output json'.split()) + self.assertEqual(cmd_res.output_format, 'json') + + cmd_res = p.execute('n1 -a x --output table'.split()) + self.assertEqual(cmd_res.output_format, 'table') + + cmd_res = p.execute('n1 -a x --output text'.split()) + self.assertEqual(cmd_res.output_format, 'text') + + # Invalid format + cmd_res = p.execute('n1 -a x --output unknown'.split()) + self.assertEqual(cmd_res.output_format, None) + + # Invalid format + cmd_res = p.execute('n1 -a x --output'.split()) + self.assertEqual(cmd_res.output_format, None) if __name__ == '__main__': unittest.main() diff --git a/src/azure/cli/tests/test_autocommand.py b/src/azure/cli/tests/test_autocommand.py index 7cc8fddabe2..d352455adff 100644 --- a/src/azure/cli/tests/test_autocommand.py +++ b/src/azure/cli/tests/test_autocommand.py @@ -72,8 +72,8 @@ def testfunc(args, _): p = ArgumentParser('automcommandtest') add_to_parser(p, 'test') - result = p.execute(command_name.split(' ') + '--tre wombat'.split(' ')) - self.assertEqual(result, func) + cmd_res = p.execute(command_name.split(' ') + '--tre wombat'.split(' ')) + self.assertEqual(cmd_res.result, func) if __name__ == '__main__': unittest.main()