-
Notifications
You must be signed in to change notification settings - Fork 716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cloud nat template #429
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Cloud NAT | ||
|
||
This template creates a Cloud NAT. | ||
|
||
## Prerequisites | ||
|
||
- Install [gcloud](https://cloud.google.com/sdk) | ||
- Create a [GCP project, set up billing, enable requisite APIs](../project/README.md) | ||
- Create a [network](../network/README.md) | ||
- Grant the [compute.networkAdmin](https://cloud.google.com/compute/docs/access/iam) IAM role to the project service account | ||
|
||
## Deployment | ||
|
||
### Resources | ||
|
||
- [compute.v1.router](https://cloud.google.com/compute/docs/reference/rest/beta/routers) | ||
|
||
### Properties | ||
|
||
See the `properties` section in the schema file(s): | ||
- [Cloud NAT](cloud_nat.py.schema) | ||
|
||
### Usage | ||
|
||
1. Clone the [Cloud Foundation Toolkit Template repository](https://github.com/GoogleCloudPlatform/deploymentmanager-samples): | ||
|
||
``` | ||
git clone https://github.com/GoogleCloudPlatform/deploymentmanager-samples.git | ||
``` | ||
|
||
2. Go to the [templates](templates/) directory: | ||
|
||
``` | ||
cd templates | ||
``` | ||
|
||
3. Copy the example DM config to be used as a model for the deployment; in this case, [examples/cloud_nat.yaml](examples/cloud_nat.yaml): | ||
|
||
``` | ||
cp templates/cloud_nat/examples/cloud_nat.yaml my_cloud_nat.yaml | ||
``` | ||
|
||
4. Change the values in the config file to match your specific GCP setup (for properties, refer to the schema files listed above): | ||
|
||
``` | ||
vim my_cloud_nat.yaml # <== change values to match your GCP setup | ||
``` | ||
|
||
5. Create your deployment (replace <YOUR_DEPLOYMENT_NAME> with the relevant deployment name): | ||
|
||
``` | ||
gcloud deployment-manager deployments create <YOUR_DEPLOYMENT_NAME> \ | ||
--config my_cloud_nat.yaml | ||
``` | ||
|
||
6. In case you need to delete your deployment: | ||
|
||
``` | ||
gcloud deployment-manager deployments delete <YOUR_DEPLOYMENT_NAME> | ||
``` | ||
|
||
## Examples | ||
|
||
- [Cloud NAT](examples/cloud_nat.yaml) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
""" This template creates a Cloud NAT. """ | ||
MIN_PORTS_PER_VM = 64 | ||
UDP_IDLE_TIMEOUT_SEC = 30 | ||
ICMP_IDLE_TIMEOUT_SEC = 30 | ||
TCP_ESTABLISHED_IDLE_TIMEOUT_SEC = 1200 | ||
TCP_TRANSITORY_IDLE_TIMEOUT_SEC = 30 | ||
|
||
def get_nat_ip_option_enum(natips): | ||
""" Returns one of the two supported Enum for Nat IP Option | ||
AUTO_ONLY or MANUAL_ONLY """ | ||
if natips: | ||
return 'MANUAL_ONLY' | ||
return 'AUTO_ONLY' | ||
|
||
def generate_config(context): | ||
""" Entry point for the deployment resources. """ | ||
|
||
name = context.properties.get('name', context.env['name']) | ||
|
||
resources = [ | ||
{ | ||
'name': context.env['name'], | ||
# compute.v1.router seems to be doing the job though | ||
# doc says compute.beta has the NAT feature. | ||
'type': 'compute.v1.router', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please use gcp-types/compute-v1:routers as type, we are moving towards the GCP types. |
||
'properties': | ||
{ | ||
'name': | ||
name, | ||
'network': | ||
generate_network_url( | ||
context, | ||
context.properties['network'] | ||
), | ||
'region': | ||
context.properties['region'], | ||
'nats': | ||
[{ | ||
'name': name, | ||
# Force using All subnet all primary IP range by default | ||
# Force using one of the two enums below: | ||
# ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES and | ||
# ALL_SUBNETWORKS_ALL_IP_RANGES | ||
'sourceSubnetworkIpRangesToNat': context.properties.get( | ||
'sourceSubnetworkIpRangesToNat', | ||
'ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES'), | ||
'natIps': context.properties.get('natIps', []), | ||
'natIpAllocateOption': get_nat_ip_option_enum( | ||
context.properties.get('natIps')), | ||
# A min of 64, anything below will | ||
# still be translated to 64 ports | ||
'minPortsPerVm': context.properties.get( | ||
'minPortsPerVm', MIN_PORTS_PER_VM), | ||
'udpIdleTimeoutSec': context.properties.get( | ||
'udpIdleTimeoutSec', UDP_IDLE_TIMEOUT_SEC), | ||
'icmpIdleTimeoutSec': context.properties.get( | ||
'icmpIdleTimeoutSec', ICMP_IDLE_TIMEOUT_SEC), | ||
'tcpEstablishedIdleTimeoutSec': context.properties.get( | ||
'tcpEstablishedIdleTimeoutSec', | ||
TCP_ESTABLISHED_IDLE_TIMEOUT_SEC), | ||
'tcpTransitoryIdleTimeoutSec': context.properties.get( | ||
'tcpTransitoryIdleTimeoutSec', | ||
TCP_TRANSITORY_IDLE_TIMEOUT_SEC) | ||
}] | ||
} | ||
} | ||
] | ||
|
||
return { | ||
'resources': | ||
resources, | ||
'outputs': | ||
[ | ||
{ | ||
'name': 'name', | ||
'value': name | ||
}, | ||
{ | ||
'name': 'selfLink', | ||
'value': '$(ref.' + context.env['name'] + '.selfLink)' | ||
}, | ||
{ | ||
'name': | ||
'nats', | ||
'value': | ||
'$(ref.' + context.env['name'] + '.nats)' | ||
} | ||
] | ||
} | ||
|
||
|
||
def generate_network_url(context, network): | ||
"""Format the resource name as a resource URI.""" | ||
|
||
return 'projects/{}/global/networks/{}'.format( | ||
context.env['project'], | ||
network | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
info: | ||
title: Cloud Nat | ||
author: [email protected] | ||
description: | | ||
Deploys a Cloud Nat. | ||
|
||
For more information on this resource: | ||
https://cloud.google.com/nat/docs/overview | ||
|
||
imports: | ||
- path: cloud_nat.py | ||
|
||
required: | ||
- network | ||
- region | ||
- name | ||
- sourceSubnetworkIpRangesToNat | ||
|
||
properties: | ||
name: | ||
type: string | ||
description: The name of Cloud Nat the resource. | ||
network: | ||
type: string | ||
description: The name of the network to which the Cloud Nat belongs. | ||
region: | ||
type: string | ||
description: The URI of the region where the Cloud Nat resides. | ||
sourceSubnetworkIpRangesToNat: | ||
type: string | ||
description: IP Range inside the VPC effected by the nats service. | ||
enum: | ||
- ALL_SUBNETWORKS_ALL_IP_RANGES | ||
- ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES | ||
minPortsPerVm: | ||
type: number | ||
description: | | ||
Minimum number of ports allocated to a VM from this NAT config, | ||
any setting belong 64 will be automatically converted to 64 | ||
udpIdleTimeoutSec: | ||
type: number | ||
description: Timeout for UDP connections in seconds | ||
default: 30 | ||
icmpIdleTimeoutSec: | ||
type: number | ||
description: Timeout for ICMP connections in seconds | ||
default: 30 | ||
tcpEstablishedIdleTimeoutSec: | ||
type: number | ||
description: Timeout for established TCP connections in seconds | ||
default: 1200 | ||
tcpTransitoryIdleTimeoutSec: | ||
type: number | ||
description: Timeout for TCP connections in seconds | ||
default: 30 | ||
natIps: | ||
type: array | ||
description: Static External IPs used as the NAT IPs. | ||
items: | ||
type: string | ||
description: Static External IP self link | ||
|
||
outputs: | ||
properties: | ||
- name: | ||
type: string | ||
description: The name of the Cloud Nat resource. | ||
- selfLink: | ||
type: string | ||
description: The URI (SelfLink) of the Cloud Nat resource. | ||
- nat: | ||
type: object | ||
description: | | ||
Object containing NAT information. | ||
https://cloud.google.com/compute/docs/reference/rest/beta/routers | ||
|
||
documentation: | ||
- templates/cloud_nat/README.md | ||
|
||
examples: | ||
- templates/cloud_nat/examples/cloud_nat.yaml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Example of the Cloud NAT template usage. | ||
# Replace <FIXME:> with your resource names | ||
|
||
imports: | ||
- path: templates/cloud_nat/cloud_nat.py | ||
name: cloud_nat.py | ||
|
||
resources: | ||
- name: cloud-nat | ||
type: cloud_nat.py | ||
properties: | ||
name: nat | ||
network: <FIXME:YOURNETWORKNAME> | ||
region: us-east1 | ||
sourceSubnetworkIpRangesToNat: ALL_SUBNETWORKS_ALL_IP_RANGES | ||
minPortsPerVm: 64 | ||
udpIdleTimeoutSec: 30 | ||
icmpIdleTimeoutSec: 30 | ||
tcpEstablishedIdleTimeoutSec: 1200 | ||
tcpTransitoryIdleTimeoutSec: 30 | ||
natIps: | ||
- projects/<FIXME:YOURPROJECTNAME>/regions/us-east1/addresses/<FIXME:YOURIPNAME> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#!/usr/bin/env bats | ||
|
||
source tests/helpers.bash | ||
|
||
TEST_NAME=$(basename "${BATS_TEST_FILENAME}" | cut -d '.' -f 1) | ||
|
||
# Create a random 10-char string and save it in a file. | ||
RANDOM_FILE="/tmp/${CLOUD_FOUNDATION_ORGANIZATION_ID}-${TEST_NAME}.txt" | ||
if [[ ! -e "${RANDOM_FILE}" ]]; then | ||
RAND=$(head /dev/urandom | LC_ALL=C tr -dc a-z0-9 | head -c 10) | ||
echo ${RAND} > "${RANDOM_FILE}" | ||
fi | ||
|
||
# Set variables based on the random string saved in the file. | ||
# envsubst requires all variables used in the example/config to be exported. | ||
if [[ -e "${RANDOM_FILE}" ]]; then | ||
export RAND=$(cat "${RANDOM_FILE}") | ||
DEPLOYMENT_NAME="${CLOUD_FOUNDATION_PROJECT_ID}-${TEST_NAME}-${RAND}" | ||
# Replace underscores with dashes in the deployment name. | ||
DEPLOYMENT_NAME=${DEPLOYMENT_NAME//_/-} | ||
CONFIG=".${DEPLOYMENT_NAME}.yaml" | ||
fi | ||
|
||
########## HELPER FUNCTIONS ########## | ||
|
||
function create_config() { | ||
echo "Creating ${CONFIG}" | ||
envsubst < "templates/cloud_nat/tests/integration/${TEST_NAME}.yaml" > "${CONFIG}" | ||
} | ||
|
||
function delete_config() { | ||
echo "Deleting ${CONFIG}" | ||
rm -f "${CONFIG}" | ||
} | ||
|
||
function setup() { | ||
# Global setup; executed once per test file. | ||
if [ ${BATS_TEST_NUMBER} -eq 1 ]; then | ||
gcloud compute networks create network-${RAND} \ | ||
--project "${CLOUD_FOUNDATION_PROJECT_ID}" \ | ||
--description "integration test ${RAND}" \ | ||
--subnet-mode custom | ||
gcloud compute addresses create ip-${RAND} \ | ||
--region us-east1 \ | ||
--project "${CLOUD_FOUNDATION_PROJECT_ID}" | ||
create_config | ||
fi | ||
|
||
# Per-test setup steps. | ||
} | ||
|
||
function teardown() { | ||
# Global teardown; executed once per test file. | ||
if [[ "$BATS_TEST_NUMBER" -eq "${#BATS_TEST_NAMES[@]}" ]]; then | ||
gcloud compute networks delete network-${RAND} \ | ||
--project "${CLOUD_FOUNDATION_PROJECT_ID}" -q | ||
gcloud compute addresses delete ip-${RAND} -q --region us-east1 | ||
rm -f "${RANDOM_FILE}" | ||
delete_config | ||
fi | ||
|
||
# Per-test teardown steps. | ||
} | ||
|
||
|
||
@test "Creating deployment ${DEPLOYMENT_NAME} from ${CONFIG}" { | ||
gcloud deployment-manager deployments create "${DEPLOYMENT_NAME}" \ | ||
--config ${CONFIG} \ | ||
--project "${CLOUD_FOUNDATION_PROJECT_ID}" | ||
} | ||
|
||
@test "Verifying that NATS were created in deployment ${DEPLOYMENT_NAME}" { | ||
run gcloud compute routers nats describe nat-"${RAND}" --router=cloud-nat-"${RAND}" --region=us-east1 --project "${CLOUD_FOUNDATION_PROJECT_ID}" | ||
echo '---Verification Output Start---' | ||
echo "$output" | ||
echo '---Verification Output Complete---' | ||
[[ "$output" =~ "icmpIdleTimeoutSec: 60" ]] | ||
[[ "$output" =~ "minPortsPerVm: 96" ]] | ||
[[ "$output" =~ "name: nat-${RAND}" ]] | ||
[[ "$output" =~ "tcpEstablishedIdleTimeoutSec: 1140" ]] | ||
[[ "$output" =~ "tcpTransitoryIdleTimeoutSec: 60" ]] | ||
[[ "$output" =~ "udpIdleTimeoutSec: 55" ]] | ||
[[ "$output" =~ "/regions/us-east1/addresses/ip-${RAND}" ]] | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please add the test from HA NAT which actually creates an pivate instance and able to reach the internet? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you mean the same as this test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I would be happy to see an instance using the managed NAT ( and maybe one not using it) and verifying it's internet connectivity via SSH. |
||
@test "Deleting deployment" { | ||
gcloud deployment-manager deployments delete "${DEPLOYMENT_NAME}" \ | ||
--project "${CLOUD_FOUNDATION_PROJECT_ID}" -q | ||
|
||
run gcloud compute nats list --project "${CLOUD_FOUNDATION_PROJECT_ID}" | ||
[[ ! "$output" =~ "name: cloud-nat-${RAND}" ]] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Test of the Cloud Router template usage. | ||
# | ||
# Variables: | ||
# RAND: a random string used by the testing suite. | ||
# | ||
|
||
imports: | ||
- path: templates/cloud_nat/cloud_nat.py | ||
name: cloud_nat.py | ||
|
||
resources: | ||
- name: cloud-nat-${RAND} | ||
type: cloud_nat.py | ||
properties: | ||
name: nat-${RAND} | ||
network: network-${RAND} | ||
region: us-east1 | ||
# ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES | ||
sourceSubnetworkIpRangesToNat: ALL_SUBNETWORKS_ALL_IP_RANGES | ||
minPortsPerVm: 96 | ||
udpIdleTimeoutSec: 55 | ||
icmpIdleTimeoutSec: 60 | ||
tcpEstablishedIdleTimeoutSec: 1140 | ||
tcpTransitoryIdleTimeoutSec: 60 | ||
natIps: | ||
- projects/${CLOUD_FOUNDATION_PROJECT_ID}/regions/us-east1/addresses/ip-${RAND} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://cloud.google.com/compute/docs/reference/rest/v1/routers Managed NAT got GA, so itś part of compute.v1