From d8147f62261bb4186c702813c42151e1f92e3fd2 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Tue, 24 May 2016 11:14:39 -0400 Subject: [PATCH 1/8] Support for newer networking modes in GCE --- cloud/google/gce_net.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index 5a1852ac9ec..174ceba6716 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -111,6 +111,14 @@ options: required: false default: null aliases: [] + mode: + version_added: TBD + description: + - network mode supporting subnets introduced into Google Cloud + required: false + default: "legacy" + choices: ["legacy", "auto", "custom"] + aliases: [] requirements: - "python >= 2.6" @@ -197,6 +205,7 @@ def main(): pem_file = dict(), credentials_file = dict(), project_id = dict(), + mode = dict(default='legacy', choices=['legacy', 'auto', 'custom']), ) ) @@ -213,6 +222,7 @@ def main(): src_tags = module.params.get('src_tags') target_tags = module.params.get('target_tags') state = module.params.get('state') + mode = module.params.get('mode') changed = False json_output = {'state': state} @@ -235,7 +245,7 @@ def main(): changed=False) try: - network = gce.ex_create_network(name, ipv4_range) + network = gce.ex_create_network(name, ipv4_range, mode=mode) json_output['name'] = name json_output['ipv4_range'] = ipv4_range changed = True From 4b5a459fc11b8c48e4cb24b61a72d25e2f5ac7f3 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Tue, 24 May 2016 14:55:38 -0400 Subject: [PATCH 2/8] Changes to allow 'auto' mode which does not allow IP address specification --- cloud/google/gce_net.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index 174ceba6716..ed2dec92e8c 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -240,12 +240,16 @@ def main(): # user wants to create a new network that doesn't yet exist if name and not network: - if not ipv4_range: - module.fail_json(msg="Network '" + name + "' is not found. To create network, 'ipv4_range' parameter is required", + if not ipv4_range and mode != 'auto': + module.fail_json(msg="Network '" + name + "' is not found. To create network in legacy mode, 'ipv4_range' parameter is required", changed=False) + if mode == 'legacy': + kwargs = {} + else: + kwargs = {'mode': mode} try: - network = gce.ex_create_network(name, ipv4_range, mode=mode) + network = gce.ex_create_network(name, ipv4_range, **kwargs) json_output['name'] = name json_output['ipv4_range'] = ipv4_range changed = True From afe17834ce0d620044e0f6b84bbba6fed67011a7 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Tue, 24 May 2016 19:20:43 +0000 Subject: [PATCH 3/8] Add error handling for specifying 'mode' with insufficiently recent libcloud --- cloud/google/gce_net.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index ed2dec92e8c..e62bc95bdaa 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -253,6 +253,8 @@ def main(): json_output['name'] = name json_output['ipv4_range'] = ipv4_range changed = True + except TypeError: + module.fail_json(msg="Update libcloud to a more recent version (1.0+) that supports network 'mode' parameter", changed=False) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) From 1ea678e4ac2127448109f475cc5fdda6ec2fb4b3 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Fri, 27 May 2016 20:03:33 +0000 Subject: [PATCH 4/8] Logic to allow subnet creation --- cloud/google/gce_net.py | 54 +++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index e62bc95bdaa..626737b68c3 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -206,6 +206,9 @@ def main(): credentials_file = dict(), project_id = dict(), mode = dict(default='legacy', choices=['legacy', 'auto', 'custom']), + subnet_name = dict(), + subnet_region = dict(), + subnet_desc = dict(), ) ) @@ -223,16 +226,25 @@ def main(): target_tags = module.params.get('target_tags') state = module.params.get('state') mode = module.params.get('mode') + subnet_name = module.params.get('subnet_name') + subnet_region = module.params.get('subnet_region') + subnet_desc = module.params.get('subnet_desc') changed = False json_output = {'state': state} if state in ['active', 'present']: network = None + subnet = None try: network = gce.ex_get_network(name) json_output['name'] = name - json_output['ipv4_range'] = network.cidr + if mode == 'legacy': + json_output['ipv4_range'] = network.cidr + if network and mode == 'custom' and subnet_name: + subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) + json_output['subnet_name'] = subnet_name + json_output['ipv4_range'] = subnet.cidr except ResourceNotFoundError: pass except Exception as e: @@ -241,23 +253,37 @@ def main(): # user wants to create a new network that doesn't yet exist if name and not network: if not ipv4_range and mode != 'auto': - module.fail_json(msg="Network '" + name + "' is not found. To create network in legacy mode, 'ipv4_range' parameter is required", + module.fail_json(msg="Network '" + name + "' is not found. To create network in legacy or custom mode, 'ipv4_range' parameter is required", changed=False) - if mode == 'legacy': - kwargs = {} - else: - kwargs = {'mode': mode} + args = [ipv4_range if mode =='legacy' else None] + kwargs = {} + if mode != 'legacy': + kwargs['mode'] = mode try: - network = gce.ex_create_network(name, ipv4_range, **kwargs) + network = gce.ex_create_network(name, *args, **kwargs) json_output['name'] = name json_output['ipv4_range'] = ipv4_range changed = True except TypeError: - module.fail_json(msg="Update libcloud to a more recent version (1.0+) that supports network 'mode' parameter", changed=False) + module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False) except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) + if (subnet_name or ipv4_range) and not subnet and mode == 'custom': + if not hasattr(gce, 'ex_create_subnetwork'): + module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed) + if not subnet_name or not ipv4_range or not subnet_region: + module.fail_json(msg="subnet_name, ipv4_range, and subnet_region required for custom mode", changed=changed) + + try: + subnet = gce.ex_create_subnetwork(subnet_name, cidr=ipv4_range, network=name, region=subnet_region, description=subnet_desc) + json_output['subnet_name'] = subnet_name + json_output['ipv4_range'] = ipv4_range + changed = True + except Exception, e: + module.fail_json(msg=unexpected_error_msg(e), changed=changed) + if fwname: # user creating a firewall rule if not allowed and not src_range and not src_tags: @@ -352,6 +378,18 @@ def main(): if fw: gce.ex_destroy_firewall(fw) changed = True + elif subnet_name: + json_output['name'] = subnet_name + subnet = None + try: + subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) + except ResourceNotFoundError: + pass + except Exception, e: + module.fail_json(msg=unexpected_error_msg(e), changed=False) + if subnet: + gce.ex_destroy_subnetwork(subnet) + changed = True elif name: json_output['name'] = name network = None From a7702c1f672ee8eae3df6d7db4e03184b8937414 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Fri, 27 May 2016 20:14:54 +0000 Subject: [PATCH 5/8] Documentation --- cloud/google/gce_net.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index 626737b68c3..1aef92474be 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -112,13 +112,34 @@ options: default: null aliases: [] mode: - version_added: TBD + version_added: "2.2" description: - network mode supporting subnets introduced into Google Cloud required: false default: "legacy" choices: ["legacy", "auto", "custom"] aliases: [] + subnet_name: + version_added: "2.2" + description: + - name of subnet to create + required: false + default: null + aliases: [] + subnet_region: + version_added: "2.2" + description: + - region of subnet to create + required: false + default: null + aliases: [] + subnet_desc: + version_added: "2.2" + description: + - description of subnet to create + required: false + default: null + aliases: [] requirements: - "python >= 2.6" From b8569ae38bc3edfe21623da615903b068f01d22e Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Fri, 27 May 2016 21:10:07 +0000 Subject: [PATCH 6/8] Additional error handling for corner cases like deleting networks with active subnetworks --- cloud/google/gce_net.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index 1aef92474be..cdca778fb49 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -263,6 +263,9 @@ def main(): if mode == 'legacy': json_output['ipv4_range'] = network.cidr if network and mode == 'custom' and subnet_name: + if not hasattr(gce, 'ex_get_subnetwork'): + module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False) + subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) json_output['subnet_name'] = subnet_name json_output['ipv4_range'] = subnet.cidr @@ -400,6 +403,8 @@ def main(): gce.ex_destroy_firewall(fw) changed = True elif subnet_name: + if not hasattr(gce, 'ex_get_subnetwork') or not hasattr(gce, 'ex_destroy_subnetwork'): + module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed) json_output['name'] = subnet_name subnet = None try: @@ -422,7 +427,12 @@ def main(): except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if network: - gce.ex_destroy_network(network) +# json_output['d4'] = 'deleting %s' % name + try: + gce.ex_destroy_network(network) + except Exception, e: + module.fail_json(msg=unexpected_error_msg(e), changed=False) +# json_output['d5'] = 'deleted %s' % name changed = True json_output['changed'] = changed From 4d9b872c3e09c30ffbf6a5e275c60f01ae2e7604 Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Fri, 3 Jun 2016 15:54:48 +0000 Subject: [PATCH 7/8] Fix exception handling to be compatible with Python 3 --- cloud/google/gce_net.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index cdca778fb49..3ee4a84f7e5 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -305,7 +305,7 @@ def main(): json_output['subnet_name'] = subnet_name json_output['ipv4_range'] = ipv4_range changed = True - except Exception, e: + except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=changed) if fwname: @@ -411,7 +411,7 @@ def main(): subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region) except ResourceNotFoundError: pass - except Exception, e: + except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) if subnet: gce.ex_destroy_subnetwork(subnet) @@ -430,7 +430,7 @@ def main(): # json_output['d4'] = 'deleting %s' % name try: gce.ex_destroy_network(network) - except Exception, e: + except Exception as e: module.fail_json(msg=unexpected_error_msg(e), changed=False) # json_output['d5'] = 'deleted %s' % name changed = True From 2de9fe0e671d4de5ede1ba579304006fad47706e Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Sat, 18 Jun 2016 09:16:37 +0000 Subject: [PATCH 8/8] Doc update --- cloud/google/gce_net.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cloud/google/gce_net.py b/cloud/google/gce_net.py index 3ee4a84f7e5..128fdb41291 100644 --- a/cloud/google/gce_net.py +++ b/cloud/google/gce_net.py @@ -114,7 +114,11 @@ options: mode: version_added: "2.2" description: - - network mode supporting subnets introduced into Google Cloud + - network mode for Google Cloud + "legacy" indicates a network with an IP address range + "auto" automatically generates subnetworks in different regions + "custom" uses networks to group subnets of user specified IP address ranges + https://cloud.google.com/compute/docs/networking#network_types required: false default: "legacy" choices: ["legacy", "auto", "custom"] @@ -162,6 +166,21 @@ EXAMPLES = ''' allowed: tcp:80,8080 src_tags: ["web", "proxy"] +# Simple example of creating a new auto network +- local_action: + module: gce_net + name: privatenet + mode: auto + +# Simple example of creating a new custom subnet +- local_action: + module: gce_net + name: privatenet + mode: custom + subnet_name: subnet_example + subnet_region: us-central1 + ipv4_range: 10.0.0.0/16 + ''' try: