You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by er...@apache.org on 2016/10/13 15:14:23 UTC
[1/4] libcloud git commit: [GCE] Added support for HTTP(S) proxies
with BackendServices
Repository: libcloud
Updated Branches:
refs/heads/trunk 065d1919d -> c873a0d34
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/aggregated_instanceGroupManagers.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/aggregated_instanceGroupManagers.json b/libcloud/test/compute/fixtures/gce/aggregated_instanceGroupManagers.json
index f42644e..0f42511 100644
--- a/libcloud/test/compute/fixtures/gce/aggregated_instanceGroupManagers.json
+++ b/libcloud/test/compute/fixtures/gce/aggregated_instanceGroupManagers.json
@@ -85,7 +85,7 @@
"name": "myinstancegroup",
"description": "my description for myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroups/myinstancegroup",
"baseInstanceName": "base-foo",
"fingerprint": "Q21hYveq9do=",
"currentActions": {
@@ -98,7 +98,7 @@
"refreshing": 0
},
"targetSize": 4,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroupManagers/myinstancegroup"
}
]
},
@@ -232,7 +232,7 @@
"zone": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b",
"name": "myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
"baseInstanceName": "myinstancegroup",
"fingerprint": "5bKcxzAnGOg=",
"currentActions": {
@@ -245,7 +245,7 @@
"refreshing": 0
},
"targetSize": 2,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroupManagers/myinstancegroup"
}
]
},
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_backendServices_web_service.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_backendServices_web_service.json b/libcloud/test/compute/fixtures/gce/global_backendServices_web_service.json
index e9af3b4..4e0e5b1 100644
--- a/libcloud/test/compute/fixtures/gce/global_backendServices_web_service.json
+++ b/libcloud/test/compute/fixtures/gce/global_backendServices_web_service.json
@@ -7,14 +7,14 @@
"backends": [
{
"description": "",
- "group": "https://www.googleapis.com/resourceviews/v1beta1/projects/project_name/zones/us-central1-b/resourceViews/us-resources",
+ "group": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
"balancingMode": "RATE",
"maxRate": 100,
"capacityScaler": 1.0
},
{
"description": "",
- "group": "https://www.googleapis.com/resourceviews/v1beta1/projects/project_name/zones/europe-west1-b/resourceViews/eu-resources",
+ "group": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
"balancingMode": "RATE",
"maxRate": 150,
"capacityScaler": 1.0
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_instanceTemplates.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_instanceTemplates.json b/libcloud/test/compute/fixtures/gce/global_instanceTemplates.json
index d2b0225..1614824 100644
--- a/libcloud/test/compute/fixtures/gce/global_instanceTemplates.json
+++ b/libcloud/test/compute/fixtures/gce/global_instanceTemplates.json
@@ -1,5 +1,5 @@
{
- "id": "projects/supertom-graphite/global/instanceTemplates",
+ "id": "projects/project_name/global/instanceTemplates",
"items": [
{
"creationTimestamp": "2016-07-18T09:53:22.323-07:00",
@@ -17,7 +17,7 @@
"initializeParams": {
"diskSizeGb": "10",
"diskType": "pd-standard",
- "sourceImage": "projects/supertom-graphite/global/images/my-new-image1"
+ "sourceImage": "projects/project_name/global/images/my-new-image1"
},
"kind": "compute#attachedDisk",
"mode": "READ_WRITE",
@@ -38,7 +38,7 @@
"type": "ONE_TO_ONE_NAT"
}
],
- "network": "https://content.googleapis.com/compute/v1/projects/supertom-graphite/global/networks/default"
+ "network": "https://content.googleapis.com/compute/v1/projects/project_name/global/networks/default"
}
],
"scheduling": {
@@ -59,9 +59,9 @@
}
]
},
- "selfLink": "https://content.googleapis.com/compute/v1/projects/supertom-graphite/global/instanceTemplates/my-instance-template1"
+ "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1"
}
],
"kind": "compute#instanceTemplateList",
- "selfLink": "https://www.googleapis.com/compute/v1/projects/supertom-graphite/global/instanceTemplates"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_instanceTemplates_insert.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_instanceTemplates_insert.json b/libcloud/test/compute/fixtures/gce/global_instanceTemplates_insert.json
new file mode 100644
index 0000000..fe35dcb
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_instanceTemplates_insert.json
@@ -0,0 +1,12 @@
+{
+ "status": "PENDING",
+ "kind": "compute#operation",
+ "name": "my_instance_template1",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my_instance_template1",
+ "operationType": "compute.instanceTemplates.insert",
+ "progress": 50,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-global_instanceTemplates_my_instance_template1_insert",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_sslcertificates.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_sslcertificates.json b/libcloud/test/compute/fixtures/gce/global_sslcertificates.json
new file mode 100644
index 0000000..170c1cb
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_sslcertificates.json
@@ -0,0 +1,16 @@
+{
+ "kind": "compute#sslCertificateList",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/sslCertificates",
+ "id": "projects/project_name/global/sslCertificates",
+ "items": [
+ {
+ "kind": "compute#sslCertificate",
+ "id": "2064539516762881220",
+ "creationTimestamp": "2016-08-30T10:28:11.926-07:00",
+ "name": "example",
+ "description": "my example ssl cert.",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/sslCertificates/example-cert",
+ "certificate": "-----BEGIN CERTIFICATE-----\nfoobar==\n-----END CERTIFICATE-----\n"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_sslcertificates_example.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_sslcertificates_example.json b/libcloud/test/compute/fixtures/gce/global_sslcertificates_example.json
new file mode 100644
index 0000000..c6a2985
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_sslcertificates_example.json
@@ -0,0 +1,10 @@
+{
+ "kind": "compute#sslCertificate",
+ "id": "2064539516762881220",
+ "creationTimestamp": "2016-08-30T10:28:11.926-07:00",
+ "name": "example",
+ "description": "my example ssl cert.",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/sslCertificates/example",
+ "certificate": "-----BEGIN CERTIFICATE-----\nfoobar==\n-----END CERTIFICATE-----\n"
+
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/global_sslcertificates_post.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_sslcertificates_post.json b/libcloud/test/compute/fixtures/gce/global_sslcertificates_post.json
new file mode 100644
index 0000000..23a9542
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_sslcertificates_post.json
@@ -0,0 +1,13 @@
+{
+ "kind": "compute#operation",
+ "id": "5564862567931215044",
+ "name": "operation-1472578091714-53b4d4e0f85d1-cf587a68-9d7a9200",
+ "operationType": "insert",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/sslCertificates/example",
+ "targetId": "2064539516762881220",
+ "status": "PENDING",
+ "user": "1294195755358-compute@developer.gserviceaccount.com",
+ "progress": 0,
+ "insertTime": "2016-08-30T10:28:11.948-07:00",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation_global_sslcertificates_post"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_global_instanceTemplates_insert.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_global_instanceTemplates_insert.json b/libcloud/test/compute/fixtures/gce/operations_operation_global_instanceTemplates_insert.json
new file mode 100644
index 0000000..274cc4f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_global_instanceTemplates_insert.json
@@ -0,0 +1,12 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "my_instance_template1",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my_instance_template1",
+ "operationType": "compute.instanceTemplates.insert",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-global_instanceTemplates_my_instance_template1_insert",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_global_sslcertificates_post.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_global_sslcertificates_post.json b/libcloud/test/compute/fixtures/gce/operations_operation_global_sslcertificates_post.json
new file mode 100644
index 0000000..73e5fbd
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_global_sslcertificates_post.json
@@ -0,0 +1,13 @@
+{
+ "kind": "compute#operation",
+ "id": "5564862567931215044",
+ "name": "operation-1472578091714-53b4d4e0f85d1-cf587a68-9d7a9200",
+ "operationType": "insert",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/sslCertificates/example",
+ "targetId": "2064539516762881220",
+ "status": "DONE",
+ "user": "1294195755358-compute@developer.gserviceaccount.com",
+ "progress": 100,
+ "insertTime": "2016-08-30T10:28:11.948-07:00",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation_global_sslcertificates_post"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_insert.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_insert.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_insert.json
new file mode 100644
index 0000000..2b6c12f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_insert.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones_us_central1_a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.insert",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_insert",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances.json
new file mode 100644
index 0000000..9e21253
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.addInstances",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_addInstances",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_delete.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_delete.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_delete.json
new file mode 100644
index 0000000..e13d017
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_delete.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.delete",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_delete",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances.json
new file mode 100644
index 0000000..a994784
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.removeInstances",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_removeInstances",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
new file mode 100644
index 0000000..e7b869e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.setNamedPorts",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_setNamedPorts",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/regions_us-east1_subnetworks_cf_972cf02e6ad49113.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/regions_us-east1_subnetworks_cf_972cf02e6ad49113.json b/libcloud/test/compute/fixtures/gce/regions_us-east1_subnetworks_cf_972cf02e6ad49113.json
new file mode 100644
index 0000000..79ac9e4
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/regions_us-east1_subnetworks_cf_972cf02e6ad49113.json
@@ -0,0 +1,11 @@
+{
+ "kind": "compute#subnetwork",
+ "id": "4297043163355844284",
+ "creationTimestamp": "2016-10-01T05:34:27.209-07:00",
+ "gatewayAddress": "10.128.0.1",
+ "name": "cf-972cf02e6ad49113",
+ "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf",
+ "ipCidrRange": "10.128.0.0/20",
+ "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49113"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers.json
index 8f6c569..c451bd6 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers.json
@@ -11,7 +11,7 @@
"zone": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a",
"name": "myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
"baseInstanceName": "myinstancegroup",
"fingerprint": "5bKcxzAnGOg=",
"currentActions": {
@@ -24,7 +24,7 @@
"refreshing": 0
},
"targetSize": 2,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroupManagers/myinstancegroup"
}
]
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers_myinstancegroup.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers_myinstancegroup.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers_myinstancegroup.json
index be0f0e7..823b5b3 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers_myinstancegroup.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroupManagers_myinstancegroup.json
@@ -7,7 +7,7 @@
"name": "myinstancegroup",
"description": "my description for myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
"baseInstanceName": "base-foo",
"fingerprint": "Q21hYveq9do=",
"currentActions": {
@@ -20,5 +20,5 @@
"refreshing": 0
},
"targetSize": 4,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroupManagers/myinstancegroup"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup.json
index ee36755..68f06e6 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup.json
@@ -4,11 +4,11 @@
"id": "1968709502073089769",
"creationTimestamp": "2016-08-11T16:53:42.413-07:00",
"zone": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a",
- "name": "managed-instance-group-1",
+ "name": "myinstancegroup",
"description": "This instance group is controlled by Instance Group Manager 'myinstancegroup'. To modify instances in this group, use the Instance Group Manager API: https://cloud.google.com/compute/docs/reference/latest/instanceGroupManagers",
"network": "https://content.googleapis.com/compute/v1/projects/project_name/global/networks/default",
"fingerprint": "42WmSpB8rSM=",
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup",
"size": 4,
"subnetwork": "https://content.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup2.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup2.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup2.json
new file mode 100644
index 0000000..f853bb7
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-a_instanceGroup_myinstancegroup2.json
@@ -0,0 +1,14 @@
+{
+
+ "kind": "compute#instanceGroup",
+ "id": "1968709502073089768",
+ "creationTimestamp": "2016-08-26T16:53:42.413-07:00",
+ "zone": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a",
+ "name": "myinstancegroup2",
+ "description": "myinstancegroup2",
+ "network": "https://content.googleapis.com/compute/v1/projects/project_name/global/networks/default",
+ "fingerprint": "42WmSpB8rSN=",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myinstancegroup2",
+ "size": 4,
+ "subnetwork": "https://content.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroupManagers_myinstancegroup.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroupManagers_myinstancegroup.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroupManagers_myinstancegroup.json
index 2385aa3..863f664 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroupManagers_myinstancegroup.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroupManagers_myinstancegroup.json
@@ -7,7 +7,7 @@
"name": "myinstancegroup",
"description": "my description for myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroups/myinstancegroup",
"baseInstanceName": "base-foo",
"fingerprint": "Q21hYveq9do=",
"currentActions": {
@@ -20,5 +20,5 @@
"refreshing": 0
},
"targetSize": 4,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroupManagers/myinstancegroup"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroup_myinstancegroup.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroup_myinstancegroup.json b/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroup_myinstancegroup.json
index c4330a8..94815c4 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroup_myinstancegroup.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-central1-b_instanceGroup_myinstancegroup.json
@@ -10,5 +10,5 @@
"fingerprint": "42WmSpB8rSM=",
"selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b/instanceGroups/myinstancegroup",
"size": 4,
- "subnetwork": "https://content.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112"
+ "subnetwork": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroupManagers.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroupManagers.json b/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroupManagers.json
index 1bf7014..1ac5d9f 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroupManagers.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroupManagers.json
@@ -11,7 +11,7 @@
"zone": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b",
"name": "myinstancegroup",
"instanceTemplate": "https://content.googleapis.com/compute/v1/projects/project_name/global/instanceTemplates/my-instance-template1",
- "instanceGroup": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
+ "instanceGroup": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
"baseInstanceName": "myinstancegroup",
"fingerprint": "5bKcxzAnGOg=",
"currentActions": {
@@ -24,7 +24,7 @@
"refreshing": 0
},
"targetSize": 2,
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroupManagers/myinstancegroup"
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroupManagers/myinstancegroup"
}
]
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroup_myinstancegroup.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroup_myinstancegroup.json b/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroup_myinstancegroup.json
index 3726373..55e9ff5 100644
--- a/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroup_myinstancegroup.json
+++ b/libcloud/test/compute/fixtures/gce/zones_us-east1-b_instanceGroup_myinstancegroup.json
@@ -8,7 +8,7 @@
"description": "This instance group is controlled by Instance Group Manager 'myinstancegroup'. To modify instances in this group, use the Instance Group Manager API: https://cloud.google.com/compute/docs/reference/latest/instanceGroupManagers",
"network": "https://content.googleapis.com/compute/v1/projects/project_name/global/networks/default",
"fingerprint": "42WmSpB8rSM=",
- "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b/instanceGroups/myinstancegroup",
"size": 4,
- "subnetwork": "https://content.googleapis.com/compute/v1/projects/project_name/regions/us-east1/subnetworks/cf-972cf02e6ad49112"
+ "subnetwork": "https://content.googleapis.com/compute/v1/projects/project_name/regions/us-east1/subnetworks/cf-972cf02e6ad49113"
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups.json
new file mode 100644
index 0000000..33a837b
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups.json
@@ -0,0 +1,29 @@
+{
+ "id": "projects/project_name/zones/us-central1-a/instanceGroups",
+ "items": [
+ {
+ "creationTimestamp": "2016-09-09T13:48:39.700-07:00",
+ "description": "",
+ "fingerprint": "42WmSpB8rSM=",
+ "id": "5837905299775594184",
+ "kind": "compute#instanceGroup",
+ "name": "myname",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "size": 0,
+ "zone": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a"
+ },
+ {
+ "creationTimestamp": "2016-09-09T13:54:30.857-07:00",
+ "description": "",
+ "fingerprint": "42WmSpB8rSM=",
+ "id": "6825641674983513961",
+ "kind": "compute#instanceGroup",
+ "name": "myname2",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname2",
+ "size": 0,
+ "zone": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a"
+ }
+ ],
+ "kind": "compute#instanceGroupList",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_insert.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_insert.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_insert.json
new file mode 100644
index 0000000..2b6c12f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_insert.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones_us_central1_a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.insert",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_insert",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname.json
new file mode 100644
index 0000000..7114fac
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname.json
@@ -0,0 +1,12 @@
+{
+
+ "kind": "compute#instanceGroup",
+ "id": "5837905299775594184",
+ "creationTimestamp": "2016-09-09T13:48:39.700-07:00",
+ "name": "myname",
+ "description": "",
+ "fingerprint": "42WmSpB8rSM=",
+ "zone": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "size": 0
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_addInstances.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_addInstances.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_addInstances.json
new file mode 100644
index 0000000..9e21253
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_addInstances.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.addInstances",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_addInstances",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_delete.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_delete.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_delete.json
new file mode 100644
index 0000000..e13d017
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_delete.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.delete",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_delete",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_listInstances.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_listInstances.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_listInstances.json
new file mode 100644
index 0000000..94c6cbf
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_listInstances.json
@@ -0,0 +1,15 @@
+{
+ "id": "projects/project_name/zones/us-central1-a/instanceGroups/myname/listInstances",
+ "items": [
+ {
+ "instance": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instances/node-name",
+ "status": "RUNNING"
+ },
+ {
+ "instance": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instances/lcnode-001",
+ "status": "RUNNING"
+ }
+ ],
+ "kind": "compute#instanceGroupsListInstances",
+ "selfLink": "https://content.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname/listInstances"
+}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_removeInstances.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_removeInstances.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_removeInstances.json
new file mode 100644
index 0000000..a994784
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_removeInstances.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.removeInstances",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_removeInstances",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_setNamedPorts.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
new file mode 100644
index 0000000..e7b869e
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instanceGroups_myname_setNamedPorts.json
@@ -0,0 +1,13 @@
+{
+ "status": "DONE",
+ "kind": "compute#operation",
+ "name": "myname",
+ "zone": "us-central1-a",
+ "insertTime": "2016-09-02T09:31:52.285-07:00",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instanceGroups/myname",
+ "operationType": "compute.instanceGroups.setNamedPorts",
+ "progress": 100,
+ "id": 123456,
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-zones_us_central1_a_instanceGroups_myname_setNamedPorts",
+ "user": "1264195755357-compute@developer.gserviceaccount.com"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/test/compute/test_gce.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_gce.py b/libcloud/test/compute/test_gce.py
index 75a53f1..9ec97e0 100644
--- a/libcloud/test/compute/test_gce.py
+++ b/libcloud/test/compute/test_gce.py
@@ -22,7 +22,7 @@ import unittest
from libcloud.utils.py3 import httplib
from libcloud.compute.drivers.gce import (
- GCENodeDriver, API_VERSION, timestamp_to_datetime, GCEAddress,
+ GCENodeDriver, API_VERSION, timestamp_to_datetime, GCEAddress, GCEBackend,
GCEBackendService, GCEFirewall, GCEForwardingRule, GCEHealthCheck,
GCENetwork, GCENodeImage, GCERoute, GCERegion, GCETargetHttpProxy,
GCEUrlMap, GCEZone, GCESubnetwork)
@@ -108,6 +108,125 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
image = self.driver._match_images(project, 'backports')
self.assertEqual(image.name, 'backports-debian-7-wheezy-v20131127')
+ def test_build_disk_gce_struct(self):
+ device_name = 'disk_name'
+ disk_name = None
+ source = self.driver.ex_get_volume('lcdisk')
+ is_boot = True
+ # source as input
+ d = self.driver._build_disk_gce_struct(
+ device_name=device_name, source=source, disk_name=disk_name,
+ is_boot=is_boot)
+ self.assertEqual(source.extra['selfLink'], d['source'])
+ self.assertTrue(d['boot'])
+ self.assertTrue(d['autoDelete'])
+ self.assertEqual('READ_WRITE', d['mode'])
+ self.assertFalse('initializeParams' in d)
+
+ # image as input
+ device_name = 'disk_name'
+ disk_type = self.driver.ex_get_disktype('pd-ssd', 'us-central1-a')
+ image = self.driver.ex_get_image('debian-7')
+ source = None
+ is_boot = True
+ d = self.driver._build_disk_gce_struct(device_name=device_name,
+ disk_type=disk_type,
+ image=image, is_boot=is_boot)
+ self.assertEqual('READ_WRITE', d['mode'])
+ self.assertEqual('PERSISTENT', d['type'])
+ self.assertTrue('initializeParams' in d and
+ isinstance(d['initializeParams'], dict))
+ self.assertTrue(
+ all(k in d['initializeParams']
+ for k in ['sourceImage', 'diskType', 'diskName']))
+ self.assertTrue(d['initializeParams']['sourceImage'].startswith(
+ 'https://'))
+ self.assertTrue(d['autoDelete'])
+ self.assertTrue(d['boot'])
+
+ def test_build_network_gce_struct(self):
+ network = self.driver.ex_get_network('lcnetwork')
+ address = self.driver.ex_get_address('lcaddress')
+ subnetwork_name = 'cf-972cf02e6ad49112'
+ subnetwork = self.driver.ex_get_subnetwork(subnetwork_name)
+ d = self.driver._build_network_gce_struct(network, subnetwork, address)
+ self.assertTrue('network' in d)
+ self.assertTrue('subnetwork' in d)
+ self.assertTrue('kind' in d and
+ d['kind'] == 'compute#instanceNetworkInterface')
+
+ network = self.driver.ex_get_network('default')
+ d = self.driver._build_network_gce_struct(network)
+ self.assertTrue('network' in d)
+ self.assertFalse('subnetwork' in d)
+ self.assertTrue('kind' in d and
+ d['kind'] == 'compute#instanceNetworkInterface')
+
+ def test_build_scheduling_gce_struct(self):
+ self.assertFalse(
+ self.driver._build_scheduling_gce_struct(None, None, None))
+ # on_host_maintenance bad value should raise a Valueerror
+ self.assertRaises(ValueError,
+ self.driver._build_service_account_gce_struct,
+ 'on_host_maintenance="foobar"')
+ # on_host_maintenance is 'MIGRATE' and prempt is True
+ self.assertRaises(ValueError,
+ self.driver._build_service_account_gce_struct,
+ 'on_host_maintenance="MIGRATE"', 'preemptible=True')
+ # automatic_restart is True and prempt is True
+ self.assertRaises(ValueError,
+ self.driver._build_service_account_gce_struct,
+ 'automatic_restart="True"', 'preemptible=True')
+
+ actual = self.driver._build_scheduling_gce_struct('TERMINATE', True,
+ False)
+ self.assertTrue('automaticRestart' in actual and
+ actual['automaticRestart'] is True)
+ self.assertTrue('onHostMaintenance' in actual and
+ actual['onHostMaintenance'] == 'TERMINATE')
+ self.assertTrue('preemptible' in actual)
+ self.assertFalse(actual['preemptible'])
+
+ def test_build_service_account_gce_struct(self):
+ self.assertRaises(ValueError,
+ self.driver._build_service_account_gce_struct, None)
+ input = {'scopes': ['compute-ro']}
+ actual = self.driver._build_service_account_gce_struct(input)
+ self.assertTrue('email' in actual)
+ self.assertTrue('scopes' in actual)
+
+ def test_build_service_account_gce_list(self):
+ # ensure we have a list
+ self.assertRaises(ValueError,
+ self.driver._build_service_accounts_gce_list, 'foo')
+ # no input
+ actual = self.driver._build_service_accounts_gce_list()
+ self.assertTrue(len(actual) == 1)
+ self.assertTrue('email' in actual[0])
+ self.assertTrue('scopes' in actual[0])
+
+ def test_get_selflink_or_name(self):
+ network = self.driver.ex_get_network('lcnetwork')
+
+ # object as input
+ actual = self.driver._get_selflink_or_name(network, False, 'network')
+ self.assertEqual('lcnetwork', actual)
+ actual = self.driver._get_selflink_or_name(network, True, 'network')
+ self.assertTrue(actual.startswith('https://'))
+
+ # name-only as input
+ actual = self.driver._get_selflink_or_name('lcnetwork', True,
+ 'network')
+ self.assertTrue(actual.startswith('https://'))
+
+ actual = self.driver._get_selflink_or_name('lcnetwork', False,
+ 'network')
+ self.assertTrue('lcnetwork', actual)
+
+ # if selflinks is true, we need objname
+ self.assertRaises(ValueError, self.driver._get_selflink_or_name,
+ 'lcnetwork', True)
+
def test_ex_get_serial_output(self):
self.assertRaises(ValueError, self.driver.ex_get_serial_output, 'foo')
node = self.driver.ex_get_node('node-name', 'us-central1-a')
@@ -213,6 +332,86 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
self.assertEqual(local_images[0].name, 'aws-ubuntu')
self.assertEqual(debian_images[1].name, 'debian-7-wheezy-v20131120')
+ def test_ex_destroy_instancegroup(self):
+ name = 'myname'
+ zone = 'us-central1-a'
+ uig = self.driver.ex_get_instancegroup(name, zone)
+ self.assertTrue(self.driver.ex_destroy_instancegroup(uig))
+
+ def test_ex_get_instancegroup(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ actual = self.driver.ex_get_instancegroup(name, loc)
+ self.assertEqual(actual.name, name)
+ self.assertEqual(actual.zone.name, loc)
+
+ def test_ex_create_instancegroup(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ actual = self.driver.ex_create_instancegroup(name, loc)
+ self.assertEqual(actual.name, name)
+ self.assertEqual(actual.zone.name, loc)
+
+ def test_ex_list_instancegroups(self):
+ loc = 'us-central1-a'
+ actual = self.driver.ex_list_instancegroups(loc)
+ self.assertTrue(len(actual) == 2)
+ self.assertEqual(actual[0].name, 'myname')
+ self.assertEqual(actual[1].name, 'myname2')
+
+ def test_ex_instancegroup_list_instances(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ gceobj = self.driver.ex_get_instancegroup(name, loc)
+ actual = self.driver.ex_instancegroup_list_instances(gceobj)
+ self.assertTrue(len(actual) == 2)
+ for node in actual:
+ self.assertTrue(isinstance(node, Node))
+ self.assertEqual(loc, node.extra['zone'].name)
+
+ def test_ex_instancegroup_add_instances(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ gceobj = self.driver.ex_get_instancegroup(name, loc)
+ node_name = self.driver.ex_get_node('node-name', loc)
+ lcnode = self.driver.ex_get_node('lcnode-001', loc)
+ node_list = [node_name, lcnode]
+ self.assertTrue(
+ self.driver.ex_instancegroup_add_instances(gceobj, node_list))
+
+ def test_ex_instancegroup_remove_instances(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ gceobj = self.driver.ex_get_instancegroup(name, loc)
+ node_name = self.driver.ex_get_node('node-name', loc)
+ lcnode = self.driver.ex_get_node('lcnode-001', loc)
+ node_list = [node_name, lcnode]
+ self.assertTrue(
+ self.driver.ex_instancegroup_remove_instances(gceobj, node_list))
+
+ def test_ex_instancegroup_set_named_ports(self):
+ name = 'myname'
+ loc = 'us-central1-a'
+ gceobj = self.driver.ex_get_instancegroup(name, loc)
+ named_ports = [{'name': 'foo', 'port': 4444}]
+ # base case
+ self.assertTrue(
+ self.driver.ex_instancegroup_set_named_ports(gceobj, named_ports))
+ # specify nothing, default is empty list
+ self.assertTrue(self.driver.ex_instancegroup_set_named_ports(gceobj))
+ # specify empty list
+ self.assertTrue(
+ self.driver.ex_instancegroup_set_named_ports(gceobj, []))
+ # raise valueerror if string is passed in
+ self.assertRaises(ValueError,
+ self.driver.ex_instancegroup_set_named_ports, gceobj,
+ 'foobar')
+ # raise valueerror if dictionary is passed in
+ self.assertRaises(ValueError,
+ self.driver.ex_instancegroup_set_named_ports, gceobj,
+ {'name': 'foo',
+ 'port': 4444})
+
def test_ex_create_instancegroupmanager(self):
name = 'myinstancegroup'
zone = 'us-central1-a'
@@ -226,6 +425,14 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
self.assertEqual(mig.size, size)
self.assertEqual(mig.zone.name, zone)
+ def test_ex_create_instancetemplate(self):
+ name = 'my-instance-template1'
+ actual = self.driver.ex_create_instancetemplate(
+ name, size='n1-standard-1', image='debian-7', network='default')
+ self.assertEqual(actual.name, name)
+ self.assertEqual(actual.extra['properties']['machineType'],
+ 'n1-standard-1')
+
def test_list_locations(self):
locations = self.driver.list_locations()
self.assertEqual(len(locations), 6)
@@ -236,6 +443,12 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
self.assertEqual(len(routes), 3)
self.assertTrue('lcdemoroute' in [route.name for route in routes])
+ def test_ex_list_sslcertificate(self):
+ ssl_name = 'example'
+ certs = self.driver.ex_list_sslcertificates()
+ self.assertEqual(certs[0].name, ssl_name)
+ self.assertTrue(len(certs) == 1)
+
def test_ex_list_subnetworks(self):
subnetworks = self.driver.ex_list_subnetworks()
self.assertEqual(len(subnetworks), 1)
@@ -244,6 +457,15 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
subnetworks = self.driver.ex_list_subnetworks('all')
self.assertEqual(len(subnetworks), 4)
+ def test_ex_create_sslcertificate(self):
+ ssl_name = 'example'
+ private_key = '-----BEGIN RSA PRIVATE KEY-----\nfoobar==\n-----END RSA PRIVATE KEY-----\n'
+ certificate = '-----BEGIN CERTIFICATE-----\nfoobar==\n-----END CERTIFICATE-----\n'
+ ssl = self.driver.ex_create_sslcertificate(
+ ssl_name, certificate=certificate, private_key=private_key)
+ self.assertEqual(ssl_name, ssl.name)
+ self.assertEqual(certificate, ssl.certificate)
+
def test_ex_create_subnetwork(self):
name = 'cf-972cf02e6ad49112'
cidr = '10.128.0.0/20'
@@ -278,6 +500,13 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
# delete with region object
self.assertTrue(self.driver.ex_destroy_subnetwork(name, region))
+ def test_ex_get_sslcertificate(self):
+ ssl_name = 'example'
+ ssl = self.driver.ex_get_sslcertificate(ssl_name)
+ self.assertEqual(ssl.name, ssl_name)
+ self.assertTrue(hasattr(ssl, 'certificate'))
+ self.assertTrue(len(ssl.certificate))
+
def test_ex_get_subnetwork(self):
name = 'cf-972cf02e6ad49112'
region_name = 'us-central1'
@@ -403,7 +632,7 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
instances = mig.list_managed_instances()
self.assertTrue(all([x['currentAction'] == 'NONE' for x in instances]))
self.assertTrue('base-foo-2vld' in [x['name'] for x in instances])
- self.assertEquals(len(instances), 4)
+ self.assertEqual(len(instances), 4)
def test_ex_list_instancetemplates(self):
instancetemplates = self.driver.ex_list_instancetemplates()
@@ -453,12 +682,40 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
self.assertTrue(isinstance(address, GCEAddress))
self.assertEqual(address.name, address_name)
+ def test_ex_create_backend(self):
+ # Note: this is an internal object, no API call is made
+ # and no fixture is needed specifically for GCEBackend, however
+ # it does rely on an InstanceGroup object.
+ ig = self.driver.ex_get_instancegroup('myinstancegroup',
+ 'us-central1-a')
+
+ backend = self.driver.ex_create_backend(ig)
+
+ self.assertTrue(isinstance(backend, GCEBackend))
+ self.assertEqual(backend.name,
+ '%s/instanceGroups/%s' % (ig.zone.name, ig.name))
+ self.assertEqual(backend.instance_group.name, ig.name)
+ self.assertEqual(backend.balancing_mode, 'UTILIZATION')
+
def test_ex_create_backendservice(self):
backendservice_name = 'web-service'
+
+ ig1 = self.driver.ex_get_instancegroup('myinstancegroup',
+ 'us-central1-a')
+ backend1 = self.driver.ex_create_backend(ig1)
+ ig2 = self.driver.ex_get_instancegroup('myinstancegroup2',
+ 'us-central1-a')
+ backend2 = self.driver.ex_create_backend(ig2)
+
backendservice = self.driver.ex_create_backendservice(
- name=backendservice_name, healthchecks=['lchealthcheck'])
+ name=backendservice_name, healthchecks=['lchealthcheck'],
+ backends=[backend1, backend2])
self.assertTrue(isinstance(backendservice, GCEBackendService))
self.assertEqual(backendservice.name, backendservice_name)
+ self.assertEqual(len(backendservice.backends), 2)
+ ig_links = [ig1.extra['selfLink'], ig2.extra['selfLink']]
+ for be in backendservice.backends:
+ self.assertTrue(be['group'] in ig_links)
def test_ex_create_healthcheck(self):
healthcheck_name = 'lchealthcheck'
@@ -486,8 +743,8 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
family = 'coreos'
guest_os_features = ['VIRTIO_SCSI_MULTIQUEUE', 'WINDOWS']
expected_features = [
- {'type': 'VIRTIO_SCSI_MULTIQUEUE'},
- {'type': 'WINDOWS'}]
+ {'type': 'VIRTIO_SCSI_MULTIQUEUE'}, {'type': 'WINDOWS'}
+ ]
mock_request = mock.Mock()
mock_request.side_effect = self.driver.connection.async_request
self.driver.connection.async_request = mock_request
@@ -516,8 +773,8 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
family = 'coreos'
guest_os_features = ['VIRTIO_SCSI_MULTIQUEUE', 'WINDOWS']
expected_features = [
- {'type': 'VIRTIO_SCSI_MULTIQUEUE'},
- {'type': 'WINDOWS'}]
+ {'type': 'VIRTIO_SCSI_MULTIQUEUE'}, {'type': 'WINDOWS'}
+ ]
image = self.driver.ex_copy_image(name, url, description=description,
family=family,
guest_os_features=guest_os_features)
@@ -676,6 +933,9 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
self.assertEqual(node_data['serviceAccounts'][0]['email'], 'default')
self.assertIsInstance(node_data['serviceAccounts'][0]['scopes'], list)
self.assertEqual(len(node_data['serviceAccounts'][0]['scopes']), 1)
+ self.assertEqual(len(node_data['networkInterfaces']), 1)
+ self.assertTrue(node_data['networkInterfaces'][0][
+ 'network'].startswith('https://'))
def test_create_node_network_opts(self):
node_name = 'node-name'
@@ -2206,6 +2466,12 @@ class GCEMockHttp(MockHttpTestCase):
body = self.fixtures.load('global_urlMaps_web_map.json')
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+ def _regions_us_east1_subnetworks_cf_972cf02e6ad49113(self, method, url,
+ body, headers):
+ body = self.fixtures.load(
+ 'regions_us-east1_subnetworks_cf_972cf02e6ad49113.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
def _regions_us_central1_subnetworks_cf_972cf02e6ad49112(self, method, url,
body, headers):
body = self.fixtures.load(
@@ -2939,6 +3205,12 @@ class GCEMockHttp(MockHttpTestCase):
'zones_us-central1-a_instanceGroup_myinstancegroup.json')
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+ def _zones_us_central1_a_instanceGroups_myinstancegroup2(self, method, url,
+ body, headers):
+ body = self.fixtures.load(
+ 'zones_us-central1-a_instanceGroup_myinstancegroup2.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
def _zones_us_central1_b_instanceGroups_myinstancegroup(self, method, url,
body, headers):
body = self.fixtures.load(
@@ -2975,7 +3247,6 @@ class GCEMockHttp(MockHttpTestCase):
'zones_us-east1-b_instanceGroupManagers.json')
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
- # TODO(supertom): this one
def _zones_us_central1_a_instanceGroupManagers(self, method, url, body,
headers):
# do an insert. Returns an operations link, which then
@@ -2995,7 +3266,19 @@ class GCEMockHttp(MockHttpTestCase):
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
def _global_instanceTemplates(self, method, url, body, headers):
- body = self.fixtures.load('global_instanceTemplates.json')
+ if method == 'POST':
+ # insert
+ body = self.fixtures.load('global_instanceTemplates_insert.json')
+ else:
+ # get or list call
+ body = self.fixtures.load('global_instanceTemplates.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _global_operations_operation_global_instanceTemplates_my_instance_template1_insert(
+ self, method, url, body, headers):
+ """ Redirects from _global_instanceTemplates """
+ body = self.fixtures.load(
+ 'operations_operation_global_instanceTemplates_insert.json')
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
def _global_instanceTemplates_my_instance_template1(self, method, url,
@@ -3008,6 +3291,109 @@ class GCEMockHttp(MockHttpTestCase):
body = self.fixtures.load('aggregated_autoscalers.json')
return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+ def _global_sslCertificates(self, method, url, body, headers):
+ if method == 'POST':
+ body = self.fixtures.load('global_sslcertificates_post.json')
+ else:
+ body = self.fixtures.load('global_sslcertificates.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _global_sslCertificates_example(self, method, url, body, headers):
+ body = self.fixtures.load('global_sslcertificates_example.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _global_operations_operation_global_sslcertificates_post(
+ self, method, url, body, headers):
+ body = self.fixtures.load(
+ 'operations_operation_global_sslcertificates_post.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups_myname(self, method, url, body,
+ headers):
+ if method == 'DELETE':
+ # delete
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname_delete.json')
+ else:
+ # get or list call
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_operations_operation_zones_us_central1_a_instanceGroups_myname_delete(
+ self, method, url, body, headers):
+ """ Redirects from _zones_us_central1_a_instanceGroups_myname """
+ body = self.fixtures.load(
+ 'operations_operation_zones_us_central1_a_instanceGroups_myname_delete.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups(self, method, url, body, headers):
+ if method == 'POST':
+ # insert
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_insert.json')
+ else:
+ # get or list call
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_operations_operation_zones_us_central1_a_instanceGroups_myname_insert(
+ self, method, url, body, headers):
+ """ Redirects from _zones_us_central1_a_instanceGroups """
+ body = self.fixtures.load(
+ 'operations_operation_zones_us_central1_a_instanceGroups_insert.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups_myname_listInstances(
+ self, method, url, body, headers):
+ # POST
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname_listInstances.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups_myname_addInstances(
+ self, method, url, body, headers):
+ # POST
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname_addInstances.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances(
+ self, method, url, body, headers):
+ """ Redirects from _zones_us_central1_a_instanceGroups_myname_addInstances """
+ body = self.fixtures.load(
+ 'operations_operation_zones_us_central1_a_instanceGroups_myname_addInstances.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups_myname_removeInstances(
+ self, method, url, body, headers):
+ # POST
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname_removeInstances.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances(
+ self, method, url, body, headers):
+ """ Redirects from _zones_us_central1_a_instanceGroups_myname_removeInstances """
+ body = self.fixtures.load(
+ 'operations_operation_zones_us_central1_a_instanceGroups_myname_removeInstances.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_instanceGroups_myname_setNamedPorts(
+ self, method, url, body, headers):
+ # POST
+ body = self.fixtures.load(
+ 'zones_us_central1_a_instanceGroups_myname_setNamedPorts.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+ def _zones_us_central1_a_operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts(
+ self, method, url, body, headers):
+ """ Redirects from _zones_us_central1_a_instanceGroups_myname_setNamedPorts """
+ body = self.fixtures.load(
+ 'operations_operation_zones_us_central1_a_instanceGroups_myname_setNamedPorts.json')
+ return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
if __name__ == '__main__':
sys.exit(unittest.main())
[2/4] libcloud git commit: [GCE] Added support for HTTP(S) proxies
with BackendServices
Posted by er...@apache.org.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/libcloud/compute/drivers/gce.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py
index 6b00491..7eaffd3 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -318,6 +318,77 @@ class GCEAddress(UuidMixin):
(hasattr(self.region, "name") and self.region.name or self.region))
+class GCEBackend(UuidMixin):
+ """A GCE Backend. Only used for creating Backend Services."""
+
+ def __init__(self, instance_group, balancing_mode='UTILIZATION',
+ max_utilization=None, max_rate=None,
+ max_rate_per_instance=None, capacity_scaler=1,
+ description=None):
+
+ if isinstance(instance_group, GCEInstanceGroup):
+ self.instance_group = instance_group
+ elif isinstance(instance_group, GCEInstanceGroupManager):
+ self.instance_group = instance_group.instance_group
+ else:
+ raise ValueError('instance_group must be of type GCEInstanceGroup'
+ 'or of type GCEInstanceGroupManager')
+
+ self.instance_group = instance_group
+ self.balancing_mode = balancing_mode
+ self.max_utilization = max_utilization
+ self.max_rate = max_rate
+ self.max_rate_per_instance = max_rate_per_instance
+ self.capacity_scaler = capacity_scaler
+
+ # 'id' and 'name' aren't actually used or provided by the GCE API.
+ # We create them for convenience.
+ self.id = self._gen_id()
+ self.name = self.id
+
+ self.description = description or self.name
+ UuidMixin.__init__(self)
+
+ def _gen_id(self):
+ """
+ Use the Instance Group information to fill in name and id fields.
+
+ :return: id in the format of:
+ ZONE/instanceGroups/INSTANCEGROUPNAME
+ Ex: us-east1-c/instanceGroups/my-instance-group
+ :rtype: ``str``
+ """
+ zone_name = self.instance_group.zone.name
+ return "%s/instanceGroups/%s" % (zone_name, self.instance_group.name)
+
+ def to_backend_dict(self):
+ """
+ Returns dict formatted for inclusion in Backend Service Request.
+
+ :return: dict formatted as a list entry for Backend Service 'backend'.
+ :rtype: ``dict``
+ """
+ d = {}
+ d['group'] = self.instance_group.extra['selfLink']
+
+ if self.balancing_mode:
+ d['balancingMode'] = self.balancing_mode
+ if self.max_utilization:
+ d['maxUtilization'] = self.max_utilization
+ if self.max_rate:
+ d['maxRate'] = self.max_rate
+ if self.max_rate_per_instance:
+ d['maxRatePerInstance'] = self.max_rate_per_instance
+ if self.capacity_scaler:
+ d['capacityScaler'] = self.capacity_scaler
+
+ return d
+
+ def __repr__(self):
+ return '<GCEBackend instancegroup="%s" balancing_mode="%s">' % (
+ self.id, self.balancing_mode)
+
+
class GCEBackendService(UuidMixin):
"""A GCE Backend Service."""
@@ -525,6 +596,67 @@ class GCENodeImage(NodeImage):
deprecated, obsolete, deleted)
+class GCESslCertificate(UuidMixin):
+ """ GCESslCertificate represents the SslCertificate resource. """
+
+ def __init__(self, id, name, certificate, driver, extra, private_key=None,
+ description=None):
+ """
+ :param name: Name of the resource. Provided by the client when the
+ resource is created. The name must be 1-63 characters
+ long, and comply with RFC1035. Specifically, the name
+ must be 1-63 characters long and match the regular
+ expression [a-z]([-a-z0-9]*[a-z0-9])? which means the
+ first character must be a lowercase letter, and all
+ following characters must be a dash, lowercase letter,
+ or digit, except the last character, which cannot be a
+ dash.
+ :type name: ``str``
+
+ :param certificate: A local certificate file. The certificate must
+ be in PEM format. The certificate chain must be
+ no greater than 5 certs long. The chain must
+ include at least one intermediate cert.
+ :type certificate: ``str``
+
+ :param private_key: A write-only private key in PEM format. Only
+ insert RPCs will include this field.
+ :type private_key: ``str``
+
+ :keyword description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :keyword driver: An initialized :class: `GCENodeDriver`
+ :type driver: :class:`:class: `GCENodeDriver``
+
+ :keyword extra: A dictionary of extra information.
+ :type extra: ``:class: ``dict````
+
+ """
+
+ self.name = name
+ self.certificate = certificate
+ self.private_key = private_key
+ self.description = description
+ self.driver = driver
+ self.extra = extra
+ UuidMixin.__init__(self)
+
+ def __repr__(self):
+ return '<GCESslCertificate name="%s">' % (self.name)
+
+ def destroy(self):
+ """
+ Destroy this SslCertificate.
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_destroy_sslcertificate(sslcertificate=self)
+
+
class GCESubnetwork(UuidMixin):
"""A GCE Subnetwork object class."""
@@ -710,8 +842,8 @@ class GCESnapshot(VolumeSnapshot):
def __init__(self, id, name, size, status, driver, extra=None,
created=None):
self.status = status
- super(GCESnapshot, self).__init__(id, driver, size, extra,
- created, name=name)
+ super(GCESnapshot, self).__init__(id, driver, size, extra, created,
+ name=name)
class GCETargetHttpProxy(UuidMixin):
@@ -736,6 +868,109 @@ class GCETargetHttpProxy(UuidMixin):
return self.driver.ex_destroy_targethttpproxy(targethttpproxy=self)
+class GCETargetHttpsProxy(UuidMixin):
+ """ GCETargetHttpsProxy represents the TargetHttpsProxy resource. """
+
+ def __init__(self, id, name, description=None, sslcertificates=None,
+ urlmap=None, driver=None, extra=None):
+ """
+ :param name: Name of the resource. Provided by the client when the
+ resource is created. The name must be 1-63 characters
+ long, and comply with RFC1035. Specifically, the name
+ must be 1-63 characters long and match the regular
+ expression [a-z]([-a-z0-9]*[a-z0-9])? which means the
+ first character must be a lowercase letter, and all
+ following characters must be a dash, lowercase letter,
+ or digit, except the last character, which cannot be a
+ dash.
+ :type name: ``str``
+
+ :param description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :param sslcertificates: URLs to SslCertificate resources that are
+ used to authenticate connections between
+ users and the load balancer. Currently,
+ exactly one SSL certificate must be
+ specified.
+ :type sslcertificates: ``list`` of :class:`GCESslcertificates`
+
+ :param urlmap: A fully-qualified or valid partial URL to the
+ UrlMap resource that defines the mapping from URL
+ to the BackendService. For example, the following
+ are all valid URLs for specifying a URL map: - ht
+ tps://www.googleapis.compute/v1/projects/project/gl
+ obal/urlMaps/url-map -
+ projects/project/global/urlMaps/url-map -
+ global/urlMaps/url-map
+ :type urlmap: :class:`GCEUrlMap`
+
+ :keyword driver: An initialized :class: `GCENodeDriver`
+ :type driver: :class:`:class: `GCENodeDriver``
+
+ :keyword extra: A dictionary of extra information.
+ :type extra: ``:class: ``dict````
+
+ """
+
+ self.name = name
+ self.description = description
+ self.sslcertificates = sslcertificates
+ self.urlmap = urlmap
+ self.driver = driver
+ self.extra = extra
+ UuidMixin.__init__(self)
+
+ def __repr__(self):
+ return '<GCETargetHttpsProxy name="%s">' % (self.name)
+
+ def set_sslcertificates(self, sslcertificates):
+ """
+ Set the SSL Certificates for this TargetHTTPSProxy
+
+ :param sslcertificates: SSL Certificates to set.
+ :type sslcertificates: ``list`` of :class:`GCESslCertificate`
+
+ :return: True if successful
+ :rtype: ``bool``
+ """
+ return self.driver.ex_targethttpsproxy_set_sslcertificates(
+ targethttpsproxy=self, sslcertificates=sslcertificates)
+
+ def set_urlmap(self, urlmap):
+ """
+ Changes the URL map for TargetHttpsProxy.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param targethttpsproxy: Name of the TargetHttpsProxy resource
+ whose URL map is to be set.
+ :type targethttpsproxy: ``str``
+
+ :param urlmap: UrlMap to set.
+ :type urlmap: :class:`GCEUrlMap`
+
+ :return: True
+ :rtype: ``bool``
+ """
+
+ return self.driver.ex_targethttpsproxy_set_urlmap(
+ targethttpsproxy=self, urlmap=urlmap)
+
+ def destroy(self):
+ """
+ Destroy this TargetHttpsProxy.
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_destroy_targethttpsproxy(targethttpsproxy=self)
+
+
class GCETargetInstance(UuidMixin):
def __init__(self, id, name, zone, node, driver, extra=None):
self.id = str(id)
@@ -803,12 +1038,21 @@ class GCEInstanceTemplate(UuidMixin):
self.id, self.name, self.extra['properties'].get('machineType',
'UNKNOWN'))
+ def destroy(self):
+ """
+ Destroy this InstanceTemplate.
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_destroy_instancetemplate(instancetemplate=self)
+
class GCEInstanceGroup(UuidMixin):
""" GCEInstanceGroup represents the InstanceGroup resource. """
- def __init__(self, id, name, zone, driver, extra=None, description=None,
- network=None, subnetwork=None, named_ports=None):
+ def __init__(self, id, name, zone, driver, extra=None, network=None,
+ subnetwork=None, named_ports=None):
"""
:param name: Required. The name of the instance group. The name
must be 1-63 characters long, and comply with RFC1035.
@@ -818,11 +1062,6 @@ class GCEInstanceGroup(UuidMixin):
located.
:type zone: :class:`GCEZone`
- :param description: An optional description of this resource.
- Provide this property when you create the
- resource.
- :type description: ``str``
-
:param network: The URL of the network to which all instances in
the instance group belong.
:type network: :class:`GCENetwork`
@@ -845,7 +1084,6 @@ class GCEInstanceGroup(UuidMixin):
self.name = name
self.zone = zone
- self.description = description
self.network = network
self.subnetwork = subnetwork
self.named_ports = named_ports
@@ -855,7 +1093,7 @@ class GCEInstanceGroup(UuidMixin):
def __repr__(self):
return '<GCEInstanceGroup name="%s" zone="%s">' % (self.name,
- self.zone)
+ self.zone.name)
def destroy(self):
"""
@@ -866,6 +1104,91 @@ class GCEInstanceGroup(UuidMixin):
"""
return self.driver.ex_destroy_instancegroup(instancegroup=self)
+ def add_instances(self, node_list):
+ """
+ Adds a list of instances to the specified instance group. All of the
+ instances in the instance group must be in the same
+ network/subnetwork. Read Adding instances for more information.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The Instance Group where you are
+ adding instances.
+ :type instancegroup: :class:``GCEInstanceGroup``
+
+ :param node_list: List of nodes to add.
+ :type node_list: ``list`` of :class:`Node` or ``list`` of
+ :class:`GCENode`
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_instancegroup_add_instances(instancegroup=self,
+ node_list=node_list)
+
+ def list_instances(self):
+ """
+ Lists the instances in the specified instance group.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+ * https://www.googleapis.com/auth/compute.readonly
+
+ :return: List of :class:`GCENode` objects.
+ :rtype: ``list`` of :class:`GCENode` objects.
+ """
+ return self.driver.ex_instancegroup_list_instances(instancegroup=self)
+
+ def remove_instances(self, node_list):
+ """
+ Removes one or more instances from the specified instance group,
+ but does not delete those instances.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The Instance Group where you are
+ removng instances.
+ :type instancegroup: :class:``GCEInstanceGroup``
+
+ :param node_list: List of nodes to add.
+ :type node_list: ``list`` of :class:`Node` or ``list`` of
+ :class:`GCENode`
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_instancegroup_remove_instances(
+ instancegroup=self, node_list=node_list)
+
+ def set_named_ports(self, named_ports):
+ """
+ Sets the named ports for the specified instance group.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param named_ports: Assigns a name to a port number. For example:
+ {name: "http", port: 80} This allows the
+ system to reference ports by the assigned name
+ instead of a port number. Named ports can also
+ contain multiple ports. For example: [{name:
+ "http", port: 80},{name: "http", port: 8080}]
+ Named ports apply to all instances in this
+ instance group.
+ :type named_ports: ``list`` of {'name': ``str``, 'port`: ``int``}
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_instancegroup_set_named_ports(
+ instancegroup=self, named_ports=named_ports)
+
class GCEInstanceGroupManager(UuidMixin):
"""
@@ -982,6 +1305,30 @@ class GCEInstanceGroupManager(UuidMixin):
return self.driver.ex_instancegroupmanager_resize(manager=self,
size=size)
+ def set_named_ports(self, named_ports):
+ """
+ Sets the named ports for the instance group controlled by this manager.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param named_ports: Assigns a name to a port number. For example:
+ {name: "http", port: 80} This allows the
+ system to reference ports by the assigned name
+ instead of a port number. Named ports can also
+ contain multiple ports. For example: [{name:
+ "http", port: 80},{name: "http", port: 8080}]
+ Named ports apply to all instances in this
+ instance group.
+ :type named_ports: ``list`` of {'name': ``str``, 'port`: ``int``}
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ return self.driver.ex_instancegroup_set_named_ports(
+ instancegroup=self.instance_group, named_ports=named_ports)
+
def __repr__(self):
return '<GCEInstanceGroupManager name="%s" zone="%s" size="%d">' % (
self.name, self.zone.name, self.size)
@@ -1297,6 +1644,7 @@ class GCENodeDriver(NodeDriver):
"windows-cloud": ["windows"],
}
+ BACKEND_SERVICE_PROTOCOLS = ['HTTP', 'HTTPS', 'HTTP2', 'TCP', 'SSL']
GUEST_OS_FEATURES = ['VIRTIO_SCSI_MULTIQUEUE', 'WINDOWS']
def __init__(self, user_id, key=None, datacenter=None, project=None,
@@ -1858,6 +2206,26 @@ class GCENodeDriver(NodeDriver):
list_routes = [self._to_route(n) for n in response.get('items', [])]
return list_routes
+ def ex_list_sslcertificates(self):
+ """
+ Retrieves the list of SslCertificate resources available to the
+ specified project.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+ * https://www.googleapis.com/auth/compute.readonly
+
+ :return: A list of SSLCertificate objects.
+ :rtype: ``list`` of :class:`GCESslCertificate`
+ """
+ list_data = []
+ request = '/global/sslCertificates'
+ response = self.connection.request(request, method='GET').object
+ list_data = [self._to_sslcertificate(a)
+ for a in response.get('items', [])]
+ return list_data
+
def ex_list_subnetworks(self, region=None):
"""
Return the list of subnetworks.
@@ -2029,6 +2397,18 @@ class GCENodeDriver(NodeDriver):
response = self.connection.request(request, method='GET').object
return [self._to_targethttpproxy(u) for u in response.get('items', [])]
+ def ex_list_targethttpsproxies(self):
+ """
+ Return the list of target HTTPs proxies.
+
+ :return: A list of target https proxy objects
+ :rtype: ``list`` of :class:`GCETargetHttpsProxy`
+ """
+ request = '/global/targetHttpsProxies'
+ response = self.connection.request(request, method='GET').object
+ return [self._to_targethttpsproxy(x)
+ for x in response.get('items', [])]
+
def ex_list_targetinstances(self, zone=None):
"""
Return the list of target instances.
@@ -2337,28 +2717,160 @@ class GCENodeDriver(NodeDriver):
data=autoscaler_data)
return self.ex_get_autoscaler(name, zone)
- def ex_create_backendservice(self, name, healthchecks):
+ def ex_create_backend(self, instance_group, balancing_mode='UTILIZATION',
+ max_utilization=None, max_rate=None,
+ max_rate_per_instance=None, capacity_scaler=1,
+ description=None):
+ """
+ Helper Object to create a backend.
+
+ :param instance_group: The Instance Group for this Backend.
+ :type instance_group: :class: `GCEInstanceGroup`
+
+ :param balancing_mode: Specifies the balancing mode for this backend.
+ For global HTTP(S) load balancing, the valid
+ values are UTILIZATION (default) and RATE.
+ For global SSL load balancing, the valid
+ values are UTILIZATION (default) and
+ CONNECTION.
+ :type balancing_mode: ``str``
+
+ :param max_utilization: Used when balancingMode is UTILIZATION.
+ This ratio defines the CPU utilization
+ target for the group. The default is 0.8.
+ Valid range is [0.0, 1.0].
+ :type max_utilization: ``float``
+
+ :param max_rate: The max requests per second (RPS) of the group.
+ Can be used with either RATE or UTILIZATION balancing
+ modes, but required if RATE mode. For RATE mode,
+ either maxRate or maxRatePerInstance must be set.
+ :type max_rate: ``int``
+
+ :param max_rate_per_instance: The max requests per second (RPS) that
+ a single backend instance can handle.
+ This is used to calculate the capacity
+ of the group. Can be used in either
+ balancing mode. For RATE mode, either
+ maxRate or maxRatePerInstance must be
+ set.
+ :type max_rate_per_instance: ``float``
+
+ :param capacity_scaler: A multiplier applied to the group's maximum
+ servicing capacity (based on UTILIZATION,
+ RATE, or CONNECTION). Default value is 1,
+ which means the group will serve up to 100%
+ of its configured capacity (depending on
+ balancingMode). A setting of 0 means the
+ group is completely drained, offering 0%
+ of its available capacity. Valid range is
+ [0.0,1.0].
+ :type capacity_scaler: ``float``
+
+ :param description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :return: A GCEBackend object.
+ :rtype: :class: `GCEBackend`
+ """
+
+ return GCEBackend(
+ instance_group=instance_group, balancing_mode=balancing_mode,
+ max_utilization=max_utilization, max_rate=max_rate,
+ max_rate_per_instance=max_rate_per_instance,
+ capacity_scaler=capacity_scaler, description=description)
+
+ def ex_create_backendservice(self, name, healthchecks, backends=[],
+ protocol=None, description=None,
+ timeout_sec=None, enable_cdn=False, port=None,
+ port_name=None):
"""
Create a global Backend Service.
- :param name: Name of the Backend Service
- :type name: ``str``
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param name: Name of the resource. Provided by the client when the
+ resource is created. The name must be 1-63 characters
+ long, and comply with RFC1035. Specifically, the name
+ must be 1-63 characters long and match the regular
+ expression [a-z]([-a-z0-9]*[a-z0-9])? which means the
+ first character must be a lowercase letter, and all
+ following characters must be a dash, lowercase letter,
+ or digit, except the last character, which cannot be a
+ dash.
+ :type name: ``str``
:param healthchecks: A list of HTTP Health Checks to use for this
service. There must be at least one.
:type healthchecks: ``list`` of (``str`` or
:class:`GCEHealthCheck`)
+ :keyword backends: The list of backends that serve this
+ BackendService.
+ :type backends: ``list`` of :class `GCEBackend` or list of ``dict``
+
+ :keyword timeout_sec: How many seconds to wait for the backend
+ before considering it a failed request.
+ Default is 30 seconds.
+ :type timeout_sec: ``integer``
+
+ :keyword enable_cdn: If true, enable Cloud CDN for this
+ BackendService. When the load balancing
+ scheme is INTERNAL, this field is not used.
+ :type enable_cdn: ``bool``
+
+ :keyword port: Deprecated in favor of port_name. The TCP port to
+ connect on the backend. The default value is 80.
+ This cannot be used for internal load balancing.
+ :type port: ``integer``
+
+ :keyword port_name: Name of backend port. The same name should appear
+ in the instance groups referenced by this service.
+ :type port_name: ``str``
+
+ :keyword protocol: The protocol this Backend Service uses to
+ communicate with backends.
+ Possible values are HTTP, HTTPS, HTTP2, TCP
+ and SSL.
+ :type protocol: ``str``
+
:return: A Backend Service object.
:rtype: :class:`GCEBackendService`
"""
- backendservice_data = {'name': name, 'healthChecks': []}
+ backendservice_data = {'name': name,
+ 'healthChecks': [],
+ 'backends': [],
+ 'enableCDN': enable_cdn}
for hc in healthchecks:
if not hasattr(hc, 'extra'):
hc = self.ex_get_healthcheck(name=hc)
backendservice_data['healthChecks'].append(hc.extra['selfLink'])
+ for be in backends:
+ if isinstance(be, GCEBackend):
+ backendservice_data['backends'].append(be.to_backend_dict())
+ else:
+ backendservice_data['backends'].append(be)
+ if port:
+ backendservice_data['port'] = port
+ if port_name:
+ backendservice_data['portName'] = port_name
+ if timeout_sec:
+ backendservice_data['timeoutSec'] = timeout_sec
+ if protocol:
+ if protocol in self.BACKEND_SERVICE_PROTOCOLS:
+ backendservice_data['protocol'] = protocol
+ else:
+ raise ValueError('Protocol must be one of %s' %
+ ','.join(self.BACKEND_SERVICE_PROTOCOLS))
+ if description:
+ backendservice_data['description'] = description
+
request = '/global/backendServices'
self.connection.async_request(request, method='POST',
data=backendservice_data)
@@ -2715,6 +3227,72 @@ class GCENodeDriver(NodeDriver):
self.connection.async_request(request, method='POST', data=image_data)
return self.ex_get_image(name)
+ def ex_create_instancegroup(self, name, zone, description=None,
+ network=None, subnetwork=None,
+ named_ports=None):
+ """
+ Creates an instance group in the specified project using the
+ parameters that are included in the request.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param name: Required. The name of the instance group. The name
+ must be 1-63 characters long, and comply with RFC1035.
+ :type name: ``str``
+
+ :param zone: The URL of the zone where the instance group is
+ located.
+ :type zone: :class:`GCEZone`
+
+ :keyword description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :keyword network: The URL of the network to which all instances in
+ the instance group belong.
+ :type network: :class:`GCENetwork`
+
+ :keyword subnetwork: The URL of the subnetwork to which all
+ instances in the instance group belong.
+ :type subnetwork: :class:`GCESubnetwork`
+
+ :keyword named_ports: Assigns a name to a port number. For example:
+ {name: "http", port: 80} This allows the
+ system to reference ports by the assigned
+ name instead of a port number. Named ports
+ can also contain multiple ports. For example:
+ [{name: "http", port: 80},{name: "http",
+ port: 8080}] Named ports apply to all
+ instances in this instance group.
+ :type named_ports: ``list`` of {'name': ``str``, 'port`: ``int``}
+
+ :return: `GCEInstanceGroup` object.
+ :rtype: :class:`GCEInstanceGroup`
+ """
+ zone = zone or self.zone
+ if not hasattr(zone, 'name'):
+ zone = self.ex_get_zone(zone)
+ request = "/zones/%s/instanceGroups" % (zone.name)
+ request_data = {}
+ request_data['name'] = name
+ request_data['zone'] = zone.extra['selfLink']
+ if description:
+ request_data['description'] = description
+ if network:
+ request_data['network'] = network.extra['selfLink']
+ if subnetwork:
+ request_data['subnetwork'] = subnetwork.extra['selfLink']
+ if named_ports:
+ request_data['namedPorts'] = named_ports
+
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return self.ex_get_instancegroup(name, zone)
+
def ex_create_instancegroupmanager(self, name, zone, template, size,
base_instance_name=None,
description=None):
@@ -2830,7 +3408,61 @@ class GCENodeDriver(NodeDriver):
return self.ex_get_route(name)
- def ex_create_subnetwork(self, name, cidr=None, network=None, region=None,
+ def ex_create_sslcertificate(self, name, certificate=None,
+ private_key=None, description=None):
+ """
+ Creates a SslCertificate resource in the specified project using the
+ data included in the request.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param name: Name of the resource. Provided by the client when the
+ resource is created. The name must be 1-63 characters
+ long, and comply with RFC1035. Specifically, the name
+ must be 1-63 characters long and match the regular
+ expression [a-z]([-a-z0-9]*[a-z0-9])? which means the
+ first character must be a lowercase letter, and all
+ following characters must be a dash, lowercase letter,
+ or digit, except the last character, which cannot be a
+ dash.
+ :type name: ``str``
+
+ :param certificate: A string containing local certificate file in
+ PEM format. The certificate chain
+ must be no greater than 5 certs long. The
+ chain must include at least one intermediate
+ cert.
+ :type certificate: ``str``
+
+ :param private_key: A string containing a write-only private key
+ in PEM format. Only insert RPCs will include
+ this field.
+ :type private_key: ``str``
+
+ :keyword description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :return: `GCESslCertificate` object.
+ :rtype: :class:`GCESslCertificate`
+ """
+
+ request = "/global/sslCertificates" % ()
+ request_data = {}
+ request_data['name'] = name
+ request_data['certificate'] = certificate
+ request_data['privateKey'] = private_key
+ request_data['description'] = description
+
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return self.ex_get_sslcertificate(name)
+
+ def ex_create_subnetwork(self, name, cidr=None, network=None, region=None,
description=None):
"""
Create a subnetwork.
@@ -3133,6 +3765,679 @@ class GCENodeDriver(NodeDriver):
self.connection.async_request(request, method='POST', data=node_data)
return self.ex_get_node(name, location.name)
+ def ex_create_instancetemplate(
+ self, name, size, source=None, image=None, disk_type='pd-standard',
+ disk_auto_delete=True, network='default', subnetwork=None,
+ can_ip_forward=None, external_ip='ephemeral',
+ service_accounts=None, on_host_maintenance=None,
+ automatic_restart=None, preemptible=None, tags=None, metadata=None,
+ description=None, disks_gce_struct=None, nic_gce_struct=None):
+ """
+ Creates an instance template in the specified project using the data
+ that is included in the request. If you are creating a new template to
+ update an existing instance group, your new instance template must
+ use the same network or, if applicable, the same subnetwork as the
+ original template.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param name: The name of the node to create.
+ :type name: ``str``
+
+ :param size: The machine type to use.
+ :type size: ``str`` or :class:`GCENodeSize`
+
+ :param image: The image to use to create the node (or, if attaching
+ a persistent disk, the image used to create the disk)
+ :type image: ``str`` or :class:`GCENodeImage` or ``None``
+
+ :keyword network: The network to associate with the template.
+ :type network: ``str`` or :class:`GCENetwork`
+
+ :keyword subnetwork: The subnetwork to associate with the node.
+ :type subnetwork: ``str`` or :class:`GCESubnetwork`
+
+ :keyword tags: A list of tags to associate with the node.
+ :type tags: ``list`` of ``str`` or ``None``
+
+ :keyword metadata: Metadata dictionary for instance.
+ :type metadata: ``dict`` or ``None``
+
+ :keyword external_ip: The external IP address to use. If 'ephemeral'
+ (default), a new non-static address will be
+ used. If 'None', then no external address will
+ be used. To use an existing static IP address,
+ a GCEAddress object should be passed in.
+ :type external_ip: :class:`GCEAddress` or ``str`` or ``None``
+
+ :keyword disk_type: Specify a pd-standard (default) disk or pd-ssd
+ for an SSD disk.
+ :type disk_type: ``str`` or :class:`GCEDiskType`
+
+ :keyword disk_auto_delete: Indicate that the boot disk should be
+ deleted when the Node is deleted. Set to
+ True by default.
+ :type disk_auto_delete: ``bool``
+
+ :keyword service_accounts: Specify a list of serviceAccounts when
+ creating the instance. The format is a
+ list of dictionaries containing email
+ and list of scopes, e.g.
+ [{'email':'default',
+ 'scopes':['compute', ...]}, ...]
+ Scopes can either be full URLs or short
+ names. If not provided, use the
+ 'default' service account email and a
+ scope of 'devstorage.read_only'. Also
+ accepts the aliases defined in
+ 'gcloud compute'.
+ :type service_accounts: ``list``
+
+ :keyword description: The description of the node (instance).
+ :type description: ``str`` or ``None``
+
+ :keyword can_ip_forward: Set to ``True`` to allow this node to
+ send/receive non-matching src/dst packets.
+ :type can_ip_forward: ``bool`` or ``None``
+
+ :keyword disks_gce_struct: Support for passing in the GCE-specific
+ formatted disks[] structure. No attempt
+ is made to ensure proper formatting of
+ the disks[] structure. Using this
+ structure obviates the need of using
+ other disk params like 'ex_boot_disk',
+ etc. See the GCE docs for specific
+ details.
+ :type disks_gce_struct: ``list`` or ``None``
+
+ :keyword nic_gce_struct: Support passing in the GCE-specific
+ formatted networkInterfaces[] structure.
+ No attempt is made to ensure proper
+ formatting of the networkInterfaces[]
+ data. Using this structure obviates the
+ need of using 'external_ip' and
+ 'ex_network'. See the GCE docs for
+ details.
+ :type nic_gce_struct: ``list`` or ``None``
+
+ :keyword on_host_maintenance: Defines whether node should be
+ terminated or migrated when host
+ machine goes down. Acceptable values
+ are: 'MIGRATE' or 'TERMINATE' (If
+ not supplied, value will be reset to
+ GCE default value for the instance
+ type.)
+ :type ex_on_host_maintenance: ``str`` or ``None``
+
+ :keyword automatic_restart: Defines whether the instance should be
+ automatically restarted when it is
+ terminated by Compute Engine. (If not
+ supplied, value will be set to the GCE
+ default value for the instance type.)
+ :type automatic_restart: ``bool`` or ``None``
+
+ :keyword preemptible: Defines whether the instance is preemptible.
+ (If not supplied, the instance will not be
+ preemptible)
+ :type preemptible: ``bool`` or ``None``
+
+ :return: An Instance Template object.
+ :rtype: :class:`GCEInstanceTemplate`
+ """
+ request = "/global/instanceTemplates"
+
+ properties = self._create_instance_properties(
+ name, node_size=size, source=source, image=image,
+ disk_type='pd-standard', disk_auto_delete=True,
+ external_ip=external_ip, network=network, subnetwork=subnetwork,
+ can_ip_forward=can_ip_forward, service_accounts=service_accounts,
+ on_host_maintenance=on_host_maintenance,
+ automatic_restart=automatic_restart, preemptible=preemptible,
+ tags=tags, metadata=metadata, description=description,
+ disks_gce_struct=disks_gce_struct, nic_gce_struct=nic_gce_struct,
+ use_selflinks=False)
+
+ request_data = {'name': name,
+ 'description': description,
+ 'properties': properties}
+
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return self.ex_get_instancetemplate(name)
+
+ def _create_instance_properties(
+ self, name, node_size, source=None, image=None,
+ disk_type='pd-standard', disk_auto_delete=True, network='default',
+ subnetwork=None, external_ip='ephemeral', can_ip_forward=None,
+ service_accounts=None, on_host_maintenance=None,
+ automatic_restart=None, preemptible=None, tags=None, metadata=None,
+ description=None, disks_gce_struct=None, nic_gce_struct=None,
+ use_selflinks=True):
+ """
+ Create the GCE instance properties needed for instance templates.
+
+ :param node_size: The machine type to use.
+ :type node_size: ``str`` or :class:`GCENodeSize`
+
+ :keyword source: A source disk to attach to the instance. Cannot
+ specify both 'image' and 'source'.
+ :type source: :class:`StorageVolume` or ``str`` or ``None``
+
+ :param image: The image to use to create the node. Cannot specify
+ both 'image' and 'source'.
+ :type image: ``str`` or :class:`GCENodeImage` or ``None``
+
+ :keyword disk_type: Specify a pd-standard (default) disk or pd-ssd
+ for an SSD disk.
+ :type disk_type: ``str`` or :class:`GCEDiskType`
+
+ :keyword disk_auto_delete: Indicate that the boot disk should be
+ deleted when the Node is deleted. Set to
+ True by default.
+ :type disk_auto_delete: ``bool``
+
+ :keyword network: The network to associate with the node.
+ :type network: ``str`` or :class:`GCENetwork`
+
+ :keyword subnetwork: The Subnetwork resource for this instance. If
+ the network resource is in legacy mode, do not
+ provide this property. If the network is in auto
+ subnet mode, providing the subnetwork is
+ optional. If the network is in custom subnet
+ mode, then this field should be specified.
+ :type subnetwork: :class: `GCESubnetwork` or None
+
+ :keyword external_ip: The external IP address to use. If 'ephemeral'
+ (default), a new non-static address will be
+ used. If 'None', then no external address will
+ be used. To use an existing static IP address,
+ a GCEAddress object should be passed in.
+ :type external_ip: :class:`GCEAddress` or ``str`` or ``None``
+
+ :keyword can_ip_forward: Set to ``True`` to allow this node to
+ send/receive non-matching src/dst packets.
+ :type can_ip_forward: ``bool`` or ``None``
+
+ :keyword service_accounts: Specify a list of serviceAccounts when
+ creating the instance. The format is a
+ list of dictionaries containing email
+ and list of scopes, e.g.
+ [{'email':'default',
+ 'scopes':['compute', ...]}, ...]
+ Scopes can either be full URLs or short
+ names. If not provided, use the
+ 'default' service account email and a
+ scope of 'devstorage.read_only'. Also
+ accepts the aliases defined in
+ 'gcloud compute'.
+ :type service_accounts: ``list``
+
+ :keyword on_host_maintenance: Defines whether node should be
+ terminated or migrated when host
+ machine goes down. Acceptable values
+ are: 'MIGRATE' or 'TERMINATE' (If
+ not supplied, value will be reset to
+ GCE default value for the instance
+ type.)
+ :type on_host_maintenance: ``str`` or ``None``
+
+ :keyword automatic_restart: Defines whether the instance should be
+ automatically restarted when it is
+ terminated by Compute Engine. (If not
+ supplied, value will be set to the GCE
+ default value for the instance type.)
+ :type automatic_restart: ``bool`` or ``None``
+
+ :keyword preemptible: Defines whether the instance is preemptible.
+ (If not supplied, the instance will not be
+ preemptible)
+ :type preemptible: ``bool`` or ``None``
+
+ :keyword tags: A list of tags to associate with the node.
+ :type tags: ``list`` of ``str`` or ``None``
+
+ :keyword metadata: Metadata dictionary for instance.
+ :type metadata: ``dict`` or ``None``
+
+ :keyword description: The description of the node (instance).
+ :type description: ``str`` or ``None``
+
+ :keyword disks_gce_struct: Support for passing in the GCE-specific
+ formatted disks[] structure. No attempt
+ is made to ensure proper formatting of
+ the disks[] structure. Using this
+ structure obviates the need of using
+ other disk params like 'boot_disk',
+ etc. See the GCE docs for specific
+ details.
+ :type disks_gce_struct: ``list`` or ``None``
+
+ :keyword nic_gce_struct: Support passing in the GCE-specific
+ formatted networkInterfaces[] structure.
+ No attempt is made to ensure proper
+ formatting of the networkInterfaces[]
+ data. Using this structure obviates the
+ need of using 'external_ip' and
+ 'network'. See the GCE docs for
+ details.
+ :type nic_gce_struct: ``list`` or ``None``
+
+ :return: A dictionary formatted for use with the GCE API.
+ :rtype: ``dict``
+ """
+ instance_properties = {}
+
+ # build disks
+ if not image and not source and not disks_gce_struct:
+ raise ValueError("Missing root device or image. Must specify an "
+ "'image', source, or use the "
+ "'disks_gce_struct'.")
+
+ if source and disks_gce_struct:
+ raise ValueError("Cannot specify both 'source' and "
+ "'disks_gce_struct'. Use one or the other.")
+
+ if disks_gce_struct:
+ instance_properties['disks'] = disks_gce_struct
+ else:
+ disk_name = None
+ device_name = None
+ if source:
+ disk_name = source.name
+ # TODO(supertom): what about device name?
+ device_name = source.name
+ image = None
+
+ instance_properties['disks'] = [self._build_disk_gce_struct(
+ device_name, source=source, disk_type=disk_type, image=image,
+ disk_name=disk_name, usage_type='PERSISTENT',
+ mount_mode='READ_WRITE', auto_delete=disk_auto_delete,
+ is_boot=True, use_selflinks=use_selflinks)]
+
+ # build network interfaces
+ if nic_gce_struct is not None:
+ if hasattr(external_ip, 'address'):
+ raise ValueError("Cannot specify both a static IP address "
+ "and 'nic_gce_struct'. Use one or the "
+ "other.")
+ if hasattr(network, 'name'):
+ if network.name == 'default':
+ # assume this is just the default value from create_node()
+ # and since the user specified ex_nic_gce_struct, the
+ # struct should take precedence
+ network = None
+ else:
+ raise ValueError("Cannot specify both 'network' and "
+ "'nic_gce_struct'. Use one or the "
+ "other.")
+ instance_properties['networkInterfaces'] = nic_gce_struct
+ else:
+ instance_properties['networkInterfaces'] = [
+ self._build_network_gce_struct(
+ network=network, subnetwork=subnetwork,
+ external_ip=external_ip, use_selflinks=True)
+ ]
+
+ # build scheduling
+ scheduling = self._build_scheduling_gce_struct(
+ on_host_maintenance, automatic_restart, preemptible)
+ if scheduling:
+ instance_properties['scheduling'] = scheduling
+
+ # build service accounts/scopes
+ instance_properties[
+ 'serviceAccounts'] = self._build_service_accounts_gce_list(
+ service_accounts)
+
+ # include general properties
+ if description:
+ instance_properties['description'] = str(description)
+ if tags:
+ instance_properties['tags'] = {'items': tags}
+ if metadata:
+ instance_properties['metadata'] = self._format_metadata(
+ fingerprint='na', metadata=metadata)
+ if can_ip_forward:
+ instance_properties['canIpForward'] = True
+
+ instance_properties['machineType'] = self._get_selflink_or_name(
+ obj=node_size, get_selflinks=use_selflinks, objname='size')
+
+ return instance_properties
+
+ def _build_disk_gce_struct(
+ self, device_name, source=None, disk_type=None, disk_size=None,
+ image=None, disk_name=None, is_boot=True, mount_mode='READ_WRITE',
+ usage_type='PERSISTENT', auto_delete=True, use_selflinks=True):
+ """
+ Generates the GCP dict for a disk.
+
+ :param device_name: Specifies a unique device name of your
+ choice that is reflected into the
+ /dev/disk/by-id/google-* tree
+ of a Linux operating system running within the
+ instance. This name can be used to reference the
+ device for mounting, resizing, and so on, from
+ within the instance. Defaults to disk_name.
+ :type device_name: ``str``
+
+ :keyword source: The disk to attach to the instance.
+ :type source: ``str`` of selfLink, :class:`StorageVolume` or None
+
+ :keyword disk_type: Specify a URL or DiskType object.
+ :type disk_type: ``str`` or :class:`GCEDiskType` or ``None``
+
+ :keyword image: The image to use to create the disk.
+ :type image: :class:`GCENodeImage` or ``None``
+
+ :keyword disk_size: Integer in gigabytes.
+ :type disk_size: ``int``
+
+ :param disk_name: Specifies the disk name. If not specified, the
+ default is to use the device_name.
+ :type disk_name: ``str``
+
+ :keyword mount_mode: The mode in which to attach this disk, either
+ READ_WRITE or READ_ONLY. If not specified,
+ the default is to attach the disk in READ_WRITE
+ mode.
+ :type mount_mode: ``str``
+
+ :keyword usage_type: Specifies the type of the disk, either SCRATCH
+ or PERSISTENT. If not specified, the default
+ is PERSISTENT.
+ :type usage_type: ``str``
+
+ :keyword auto_delete: Indicate that the boot disk should be
+ deleted when the Node is deleted. Set to
+ True by default.
+ :type auto_delete: ``bool``
+
+ :return: Dictionary to be used in disk-portion of
+ instance API call.
+ :rtype: ``dict``
+ """
+ # validation
+ if source is None and image is None:
+ raise ValueError(
+ "Either the 'source' or 'image' argument must be specified.")
+
+ if not isinstance(auto_delete, bool):
+ raise ValueError("auto_delete field is not a bool.")
+
+ if disk_size is not None and not disk_size.isdigit():
+ raise ValueError("disk_size must be a digit, '%s' provided." %
+ (disk_size))
+
+ mount_modes = ['READ_WRITE', 'READ_ONLY']
+ if mount_mode not in mount_modes:
+ raise ValueError("mount mode must be one of: %s." %
+ (','.join(mount_modes)))
+ usage_types = ['PERSISTENT', 'SCRATCH']
+ if usage_type not in usage_types:
+ raise ValueError("usage type must be one of: %s." %
+ (','.join(usage_types)))
+
+ disk = {}
+ if not disk_name:
+ disk_name = device_name
+
+ if source is not None:
+ disk['source'] = self._get_selflink_or_name(
+ obj=source, get_selflinks=use_selflinks, objname='volume')
+
+ else:
+ # create new disk
+ # we need the URL of the image, always.
+ image = self._get_selflink_or_name(obj=image, get_selflinks=True,
+ objname='image')
+ disk_type = self._get_selflink_or_name(
+ obj=disk_type, get_selflinks=use_selflinks, objname='disktype')
+
+ disk['initializeParams'] = {
+ 'diskName': disk_name,
+ 'diskType': disk_type,
+ 'sourceImage': image,
+ }
+ if disk_size is not None:
+ disk['initializeParams']['diskSizeGb'] = disk_size
+
+ # add in basic attributes
+ disk.update({'boot': is_boot,
+ 'type': usage_type,
+ 'mode': mount_mode,
+ 'deviceName': device_name,
+ 'autoDelete': auto_delete})
+ return disk
+
+ def _get_selflink_or_name(self, obj, get_selflinks=True, objname=None):
+ """
+ Return the selflink or name, given a name or object.
+
+ Will try to fetch the appropriate object if necessary (assumes
+ we only need one parameter to fetch the object, no introspection
+ is performed).
+
+ :param obj: object to test.
+ :type obj: ``str`` or ``object``
+
+ :param get_selflinks: Inform if we should return selfLinks or just
+ the name. Default is True.
+ :param get_selflinks: ``bool``
+
+ :param objname: string to use in constructing method call
+ :type objname: ``str`` or None
+
+ :return: URL from extra['selfLink'] or name
+ :rtype: ``str``
+ """
+ if get_selflinks:
+ if not hasattr(obj, 'name'):
+ if objname:
+ getobj = getattr(self, 'ex_get_%s' % (objname))
+ obj = getobj(obj)
+ else:
+ raise ValueError(
+ "objname must be set if selflinks is True.")
+ return obj.extra['selfLink']
+ else:
+ if not hasattr(obj, 'name'):
+ return obj
+ else:
+ return obj.name
+
+ def _build_network_gce_struct(self, network, subnetwork=None,
+ external_ip=None, use_selflinks=True):
+ """
+ Build network interface dict for use in the GCE API.
+
+ Note: Must be wrapped in a list before passing to the GCE API.
+
+ :param network: The network to associate with the node.
+ :type network: :class:`GCENetwork`
+
+ :keyword subnetwork: The subnetwork to include.
+ :type subnetwork: :class:`GCESubNetwork`
+
+ :keyword external_ip: The external IP address to use. If 'ephemeral'
+ (default), a new non-static address will be
+ used. If 'None', then no external address will
+ be used. To use an existing static IP address,
+ a GCEAddress object should be passed in.
+ :type external_ip: :class:`GCEAddress`
+
+ :return: network interface dict
+ :rtype: ``dict``
+ """
+ ni = {}
+ ni = {'kind': 'compute#instanceNetworkInterface'}
+ if network is None:
+ network = 'default'
+
+ ni['network'] = self._get_selflink_or_name(
+ obj=network, get_selflinks=use_selflinks, objname='network')
+
+ if subnetwork:
+ ni['subnetwork'] = self._get_selflink_or_name(
+ obj=subnetwork, get_selflinks=use_selflinks,
+ objname='subnetwork')
+
+ if external_ip:
+ access_configs = [{'name': 'External NAT',
+ 'type': 'ONE_TO_ONE_NAT'}]
+ if hasattr(external_ip, 'address'):
+ access_configs[0]['natIP'] = external_ip.address
+ ni['accessConfigs'] = access_configs
+
+ return ni
+
+ def _build_service_account_gce_struct(
+ self, service_account, default_email='default',
+ default_scope='devstorage.read_only'):
+ """
+ Helper to create Service Account dict. Use
+ _build_service_accounts_gce_list to create a list ready for the
+ GCE API.
+
+ :param: service_account: dictionarie containing email
+ and list of scopes, e.g.
+ [{'email':'default',
+ 'scopes':['compute', ...]}, ...]
+ Scopes can either be full URLs or short
+ names. If not provided, use the
+ 'default' service account email and a
+ scope of 'devstorage.read_only'. Also
+ accepts the aliases defined in
+ 'gcloud compute'.
+ :type service_account: ``dict`` or None
+
+ :return: dict usable in GCE API call.
+ :rtype: ``dict``
+ """
+ if not isinstance(service_account, dict):
+ raise ValueError(
+ "service_account not in the correct format,"
+ "'%s - %s'" %
+ (str(type(service_account)), str(service_account)))
+ sa = {}
+ if 'email' not in service_account:
+ sa['email'] = default_email
+
+ if 'scopes' not in service_account:
+ sa['scopes'] = [self.AUTH_URL + default_scope]
+ else:
+ ps = []
+ for scope in service_account['scopes']:
+ if scope.startswith(self.AUTH_URL):
+ ps.append(scope)
+ elif scope in self.SA_SCOPES_MAP:
+ ps.append(self.AUTH_URL + self.SA_SCOPES_MAP[scope])
+ else:
+ ps.append(self.AUTH_URL + scope)
+ sa['scopes'] = ps
+
+ return sa
+
+ def _build_service_accounts_gce_list(self, service_accounts=None,
+ default_email='default',
+ default_scope='devstorage.read_only'):
+ """
+ Helper to create service account list for GCE API.
+
+ :keyword service_accounts: Specify a list of serviceAccounts when
+ creating the instance. The format is a
+ list of dictionaries containing email
+ and list of scopes, e.g.
+ [{'email':'default',
+ 'scopes':['compute', ...]}, ...]
+ Scopes can either be full URLs or short
+ names. If not provided, use the
+ 'default' service account email and a
+ scope of 'devstorage.read_only'. Also
+ accepts the aliases defined in
+ 'gcloud compute'.
+
+ :type service_accounts: ``list`` of ``dict`` or None
+
+ :return: list of dictionaries usable in the GCE API.
+ :rtype: ``list`` of ``dict``
+ """
+ gce_service_accounts = []
+ if not service_accounts:
+ gce_service_accounts = [{
+ 'email': default_email,
+ 'scopes': [self.AUTH_URL + default_scope]
+ }]
+ elif not isinstance(service_accounts, list):
+ raise ValueError("service_accounts field is not a list.")
+ else:
+ for sa in service_accounts:
+ gce_service_accounts.append(
+ self._build_service_account_gce_struct(service_account=sa))
+
+ return gce_service_accounts
+
+ def _build_scheduling_gce_struct(self, on_host_maintenance=None,
+ automatic_restart=None, preemptible=None):
+ """
+ Build the scheduling dict suitable for use with the GCE API.
+
+ :param on_host_maintenance: Defines whether node should be
+ terminated or migrated when host
+ machine goes down. Acceptable values
+ are: 'MIGRATE' or 'TERMINATE' (If
+ not supplied, value will be reset to
+ GCE default value for the instance
+ type.)
+ :type on_host_maintenance: ``str`` or ``None``
+
+ :param automatic_restart: Defines whether the instance should be
+ automatically restarted when it is
+ terminated by Compute Engine. (If not
+ supplied, value will be set to the GCE
+ default value for the instance type.)
+ :type automatic_restart: ``bool`` or ``None``
+
+ :param preemptible: Defines whether the instance is preemptible.
+ (If not supplied, the instance will
+ not be preemptible)
+ :type preemptible: ``bool`` or ``None``
+
+ :return: A dictionary of scheduling options for the GCE API.
+ :rtype: ``dict``
+ """
+ scheduling = {}
+ if preemptible is not None:
+ if isinstance(preemptible, bool):
+ scheduling['preemptible'] = preemptible
+ else:
+ raise ValueError("boolean expected for preemptible")
+ if on_host_maintenance is not None:
+ maint_opts = ['MIGRATE', 'TERMINATE']
+ if isinstance(on_host_maintenance,
+ str) and on_host_maintenance in maint_opts:
+ if preemptible is True and on_host_maintenance is 'MIGRATE':
+ raise ValueError(("host maintenance cannot be 'MIGRATE' "
+ "if instance is preemptible."))
+ scheduling['onHostMaintenance'] = on_host_maintenance
+ else:
+ raise ValueError("host maintenance must be one of %s" %
+ (','.join(maint_opts)))
+ if automatic_restart is not None:
+ if isinstance(automatic_restart, bool):
+ if automatic_restart is True and preemptible is True:
+ raise ValueError(
+ "instance cannot be restarted if it is preemptible.")
+ scheduling['automaticRestart'] = automatic_restart
+
+ else:
+ raise ValueError("boolean expected for automatic")
+
+ return scheduling
+
def ex_create_multiple_nodes(
self, base_name, size, image, number, location=None,
ex_network='default', ex_tags=None, ex_metadata=None,
@@ -3376,6 +4681,61 @@ class GCENodeDriver(NodeDriver):
return self.ex_get_targethttpproxy(name)
+ def ex_create_targethttpsproxy(self, name, urlmap, sslcertificates,
+ description=None):
+ """
+ Creates a TargetHttpsProxy resource in the specified project
+ using the data included in the request.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param name: Name of the resource. Provided by the client when the
+ resource is created. The name must be 1-63 characters
+ long, and comply with RFC1035. Specifically, the name
+ must be 1-63 characters long and match the regular
+ expression [a-z]([-a-z0-9]*[a-z0-9])? which means the
+ first character must be a lowercase letter, and all
+ following characters must be a dash, lowercase letter,
+ or digit, except the last character, which cannot be a
+ dash.
+ :type name: ``str``
+
+ :param sslcertificates: URLs to SslCertificate resources that
+ are used to authenticate connections
+ between users and the load balancer.
+ Currently, exactly one SSL certificate
+ must be specified.
+ :type sslcertificates: ``list`` of :class:`GCESslcertificates`
+
+ :param urlmap: A fully-qualified or valid partial URL to the
+ UrlMap resource that defines the mapping from URL
+ to the BackendService.
+ :type urlmap: :class:`GCEUrlMap`
+
+ :keyword description: An optional description of this resource.
+ Provide this property when you create the
+ resource.
+ :type description: ``str``
+
+ :return: `GCETargetHttpsProxy` object.
+ :rtype: :class:`GCETargetHttpsProxy`
+ """
+
+ request = "/global/targetHttpsProxies" % ()
+ request_data = {}
+ request_data['name'] = name
+ request_data['description'] = description
+ request_data['sslCertificates'] = [x.extra['selfLink']
+ for x in sslcertificates]
+ request_data['urlMap'] = urlmap.extra['selfLink']
+
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return self.ex_get_targethttpsproxy(name)
+
def ex_create_targetinstance(self, name, zone=None, node=None,
description=None, nat_policy="NO_NAT"):
"""
@@ -3705,6 +5065,61 @@ class GCENodeDriver(NodeDriver):
return self.ex_get_firewall(firewall.name)
+ def ex_targethttpsproxy_set_sslcertificates(self, targethttpsproxy,
+ sslcertificates):
+ """
+ Replaces SslCertificates for TargetHttpsProxy.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param targethttpsproxy: Name of the TargetHttpsProxy resource to
+ set an SslCertificates resource for.
+ :type targethttpsproxy: ``str``
+
+ :param sslcertificates: sslcertificates to set.
+ :type sslcertificates: ``list`` of :class:`GCESslCertificates`
+
+ :return: True
+ :rtype: ``bool``
+ """
+
+ request = "/targetHttpsProxies/%s/setSslCertificates" % (
+ targethttpsproxy.name)
+ request_data = {'sslCertificates': [x.extra['selfLink']
+ for x in sslcertificates]}
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return True
+
+ def ex_targethttpsproxy_set_urlmap(self, targethttpsproxy, urlmap):
+ """
+ Changes the URL map for TargetHttpsProxy.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param targethttpsproxy: Name of the TargetHttpsProxy resource
+ whose URL map is to be set.
+ :type targethttpsproxy: ``str``
+
+ :param urlmap: urlmap to set.
+ :type urlmap: :class:`GCEUrlMap`
+
+ :return: True
+ :rtype: ``bool``
+ """
+
+ request = "/targetHttpsProxies/%s/setUrlMap" % (targethttpsproxy.name)
+ request_data = {'urlMap': urlmap.extra['selfLink']}
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+
+ return True
+
def ex_targetpool_get_health(self, targetpool, node=None):
"""
Return a hash of target pool instances and their health.
@@ -3920,6 +5335,158 @@ class GCENodeDriver(NodeDriver):
targetpool.healthchecks.pop(index)
return True
+ def ex_instancegroup_add_instances(self, instancegroup, node_list):
+ """
+ Adds a list of instances to the specified instance group. All of the
+ instances in the instance group must be in the same
+ network/subnetwork. Read Adding instances for more information.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The Instance Group where you are
+ adding instances.
+ :type instancegroup: :class:``GCEInstanceGroup``
+
+ :param node_list: List of nodes to add.
+ :type node_list: ``list`` of :class:`Node` or ``list`` of
+ :class:`GCENode`
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+ request = "/zones/%s/instanceGroups/%s/addInstances" % (
+ instancegroup.zone.name, instancegroup.name)
+ request_data = {'instances': [{'instance': x.extra['selfLink']}
+ for x in node_list]}
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+ return True
+
+ def ex_instancegroup_remove_instances(self, instancegroup, node_list):
+ """
+ Removes one or more instances from the specified instance group,
+ but does not delete those instances.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The Instance Group where the
+ specified instances will be removed.
+ :type instancegroup: :class:``GCEInstanceGroup``
+
+ :param node_list: List of nodes to add.
+ :type node_list: ``list`` of :class:`Node` or ``list`` of
+ :class:`GCENode`
+
+ :return: True if successful.
+ :rtype: ``bool``
+ """
+ request = "/zones/%s/instanceGroups/%s/removeInstances" % (
+ instancegroup.zone.name, instancegroup.name)
+ request_data = {'instances': [{'instance': x.extra['selfLink']}
+ for x in node_list]}
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+ return True
+
+ def ex_instancegroup_list_instances(self, instancegroup):
+ """
+ Lists the instances in the specified instance group.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+ * https://www.googleapis.com/auth/compute.readonly
+
+ :param instancegroup: The Instance Group where from which you
+ want to generate a list of included
+ instances.
+ :type instancegroup: :class:``GCEInstanceGroup``
+
+ :return: List of :class:`GCENode` objects.
+ :rtype: ``list`` of :class:`GCENode` objects.
+ """
+ request = "/zones/%s/instanceGroups/%s/listInstances" % (
+ instancegroup.zone.name, instancegroup.name)
+
+ # Note: This API requires a 'POST'.
+ response = self.connection.request(request, method='POST').object
+
+ list_data = []
+ if 'items' in response:
+ for v in response['items']:
+ instance_info = self._get_components_from_path(v['instance'])
+ list_data.append(
+ self.ex_get_node(instance_info['name'], instance_info[
+ 'zone']))
+ return list_data
+
+ def ex_instancegroup_set_named_ports(self, instancegroup, named_ports=[]):
+ """
+ Sets the named ports for the specified instance group.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The Instance Group where where the
+ named ports are updated.
+ :type instancegroup: :class:`GCEInstanceGroup`
+
+ :param named_ports: Assigns a name to a port number. For example:
+ {name: "http", port: 80} This allows the
+ system to reference ports by the assigned name
+ instead of a port number. Named ports can also
+ contain multiple ports. For example: [{name:
+ "http", port: 80},{name: "http", port: 8080}]
+ Named ports apply to all instances in this
+ instance group.
+ :type named_ports: ``list`` of {'name': ``str``, 'port`: ``int``}
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+
+ if not isinstance(named_ports, list):
+ raise ValueError("'named_ports' must be a list of name/port"
+ " dictionaries.")
+
+ request = "/zones/%s/instanceGroups/%s/setNamedPorts" % (
+ instancegroup.zone.name, instancegroup.name)
+ request_data = {'namedPorts': named_ports,
+ 'fingerprint': instancegroup.extra['fingerprint']}
+ self.connection.async_request(request, method='POST',
+ data=request_data)
+ return True
+
+ def ex_destroy_instancegroup(self, instancegroup):
+ """
+ Deletes the specified instance group. The instances in the group
+ are not deleted. Note that instance group must not belong to a backend
+ service. Read Deleting an instance group for more information.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancegroup: The name of the instance group to delete.
+ :type instancegroup: :class:`GCEInstanceGroup`
+
+ :return: Return True if successful.
+ :rtype: ``bool``
+ """
+
+ request = "/zones/%s/instanceGroups/%s" % (instancegroup.zone.name,
+ instancegroup.name)
+ request_data = {}
+ self.connection.async_request(request, method='DELETE',
+ data=request_data)
+
+ return True
+
def ex_instancegroupmanager_list_managed_instances(self, manager):
"""
Lists all of the instances in the Managed Instance Group.
@@ -4479,8 +6046,8 @@ class GCENodeDriver(NodeDriver):
try:
timestamp_to_datetime(value)
except:
- raise ValueError('%s must be an RFC3339 timestamp'
- % attribute)
+ raise ValueError('%s must be an RFC3339 timestamp' %
+ attribute)
image_data[attribute] = value
request = '/global/images/%s/deprecate' % (image.name)
@@ -4634,6 +6201,33 @@ class GCENodeDriver(NodeDriver):
self.connection.async_request(request, method='DELETE')
return True
+ def ex_destroy_instancetemplate(self, instancetemplate):
+ """
+ Deletes the specified instance template. If you delete an instance
+ template that is being referenced from another instance group, the
+ instance group will not be able to create or recreate virtual machine
+ instances. Deleting an instance template is permanent and cannot be
+ undone.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param instancetemplate: The name of the instance template to
+ delete.
+ :type instancetemplate: ``str``
+
+ :return instanceTemplate: Return True if successful.
+ :rtype instanceTemplate: ````bool````
+ """
+
+ request = "/global/instanceTemplates/%s" % (instancetemplate.name)
+ request_data = {}
+ self.connection.async_request(request, method='DELETE',
+ data=request_data)
+
+ return True
+
def ex_destroy_autoscaler(self, autoscaler):
"""
Destroy an Autoscaler.
@@ -4792,6 +6386,29 @@ class GCENodeDriver(NodeDriver):
self.connection.async_request(request, method='DELETE')
return True
+ def ex_destroy_targethttpsproxy(self, targethttpsproxy):
+ """
+ Deletes the specified TargetHttpsProxy resource.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param targethttpsproxy: Name of the TargetHttpsProxy resource to
+ delete.
+ :type targethttpsproxy: ``str``
+
+ :return targetHttpsProxy: Return True if successful.
+ :rtype targetHttpsProxy: ````bool````
+ """
+
+ request = "/global/targetHttpsProxies/%s" % (targethttpsproxy.name)
+ request_data = {}
+ self.connection.async_request(request, method='DELETE',
+ data=request_data)
+
+ return True
+
def ex_destroy_targetinstance(self, targetinstance):
"""
Destroy a target instance.
@@ -5109,6 +6726,29 @@ class GCENodeDriver(NodeDriver):
response = self.connection.request(request, method='GET').object
return self._to_route(response)
+ def ex_destroy_sslcertificate(self, sslcertificate):
+ """
+ Deletes the specified SslCertificate resource.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+
+ :param sslcertificate: Name of the SslCertificate resource to
+ delete.
+ :type sslcertificate: ``str``
+
+ :return sslCertificate: Return True if successful.
+ :rtype sslCertificate: ````bool````
+ """
+
+ request = "/global/sslCertificates/%s" % (sslcertificate.name)
+ request_data = {}
+ self.connection.async_request(request, method='DELETE',
+ data=request_data)
+
+ return True
+
def ex_destroy_subnetwork(self, name, region=None):
"""
Delete a Subnetwork object based on name and region.
@@ -5318,6 +6958,29 @@ class GCENodeDriver(NodeDriver):
response = self.connection.request(request, method='GET').object
return self._to_region(response)
+ def ex_get_sslcertificate(self, name):
+ """
+ Returns the specified SslCertificate resource. Get a list of available
+ SSL certificates by making a list() request.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+ * https://www.googleapis.com/auth/compute.readonly
+
+ :param name: Name of the SslCertificate resource to
+ return.
+ :type name: ``str``
+
+ :return: `GCESslCertificate` object.
+ :rtype: :class:`GCESslCertificate`
+ """
+
+ request = "/global/sslCertificates/%s" % (name)
+ response = self.connection.request(request, method='GET').object
+
+ return self._to_sslcertificate(response)
+
def ex_get_targethttpproxy(self, name):
"""
Return a Target HTTP Proxy object based on its name.
@@ -5332,6 +6995,29 @@ class GCENodeDriver(NodeDriver):
response = self.connection.request(request, method='GET').object
return self._to_targethttpproxy(response)
+ def ex_get_targethttpsproxy(self, name):
+ """
+ Returns the specified TargetHttpsProxy resource. Get a list of
+ available target HTTPS proxies by making a list() request.
+
+ Scopes needed - one of the following:
+ * https://www.googleapis.com/auth/cloud-platform
+ * https://www.googleapis.com/auth/compute
+ * https://www.googleapis.com/auth/compute.readonly
+
+ :param name: Name of the TargetHttpsProxy resource to
+ return.
+ :type name: ``str``
+
+ :return: `GCETargetHttpsProxy` object.
+ :rtype: :class:`GCETargetHttpsProxy`
+ """
+
+ request = "/global/targetHttpsProxies/%s" % (name)
+ response = self.connection.request(request, method='GET').object
+
+ return self._to_targethttpsproxy(response)
+
def ex_get_targetinstance(self, name, zone=None):
"""
Return a TargetInstance object based on a name and optional zone.
@@ -5700,8 +7386,9 @@ class GCENodeDriver(NodeDriver):
ex_on_host_maintenance=None, ex_automatic_restart=None,
ex_preemptible=None, ex_subnetwork=None):
"""
- Returns a request and body to create a new node. This is a helper
- method to support both :class:`create_node` and
+ Returns a request and body to create a new node.
+
+ This is a helper method to support both :class:`create_node` and
:class:`ex_create_multiple_nodes`.
:param name: The name of the node to create.
@@ -5815,140 +7502,34 @@ class GCENodeDriver(NodeDriver):
:return: A tuple containing a request string and a node_data dict.
:rtype: ``tuple`` of ``str`` and ``dict``
"""
- node_data = {}
- node_data['machineType'] = size.extra['selfLink']
- node_data['name'] = name
- if tags:
- node_data['tags'] = {'items': tags}
- if metadata:
- node_data['metadata'] = self._format_metadata(fingerprint='na',
- metadata=metadata)
-
- # by default, new instances will match the same serviceAccount and
- # scope set in the Developers Console and Cloud SDK
- if not ex_service_accounts:
- set_scopes = [{
- 'email': 'default',
- 'scopes': [self.AUTH_URL + 'devstorage.read_only']
- }]
- elif not isinstance(ex_service_accounts, list):
- raise ValueError("ex_service_accounts field is not a list.")
- else:
- set_scopes = []
- for sa in ex_service_accounts:
- if not isinstance(sa, dict):
- raise ValueError("ex_service_accounts needs to be a list "
- "of dicts, got: '%s - %s'" %
- (str(type(sa)), str(sa)))
- if 'email' not in sa:
- sa['email'] = 'default'
- if 'scopes' not in sa:
- sa['scopes'] = [self.AUTH_URL + 'devstorage.read_only']
- ps = []
- for scope in sa['scopes']:
- if scope.startswith(self.AUTH_URL):
- ps.append(scope)
- elif scope in self.SA_SCOPES_MAP:
- ps.append(self.AUTH_URL + self.SA_SCOPES_MAP[scope])
- else:
- ps.append(self.AUTH_URL + scope)
- sa['scopes'] = ps
- set_scopes.append(sa)
- node_data['serviceAccounts'] = set_scopes
-
- if boot_disk and ex_disks_gce_struct:
- raise ValueError("Cannot specify both 'boot_disk' and "
- "'ex_disks_gce_s
<TRUNCATED>
[4/4] libcloud git commit: update changes
Posted by er...@apache.org.
update changes
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c873a0d3
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c873a0d3
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c873a0d3
Branch: refs/heads/trunk
Commit: c873a0d34a8188fd5e2475023f1b26fb063ef51e
Parents: cffd964
Author: Eric Johnson <er...@google.com>
Authored: Thu Oct 13 15:13:59 2016 +0000
Committer: Eric Johnson <er...@google.com>
Committed: Thu Oct 13 15:13:59 2016 +0000
----------------------------------------------------------------------
CHANGES.rst | 4 ++++
1 file changed, 4 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c873a0d3/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 38fd531..9d834c0 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -12,6 +12,10 @@ Compute
(GITHUB-897)
[Anthony Monthe]
+- [GCE] Support for HTTP(S) proxies with BackendServices
+ (GITHUB-856
+ [Tom Melendez]
+
Changes in Apache Libcloud 1.3.0
--------------------------------
[3/4] libcloud git commit: [GCE] Added support for HTTP(S) proxies
with BackendServices
Posted by er...@apache.org.
[GCE] Added support for HTTP(S) proxies with BackendServices
Closes #856
Signed-off-by: Eric Johnson <er...@google.com>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/cffd9642
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/cffd9642
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/cffd9642
Branch: refs/heads/trunk
Commit: cffd96420e9e86f213b7c08d00d548d9096fa7cb
Parents: 065d191
Author: Tom Melendez <su...@google.com>
Authored: Thu Aug 25 23:57:27 2016 +0000
Committer: Eric Johnson <er...@google.com>
Committed: Thu Oct 13 15:12:39 2016 +0000
----------------------------------------------------------------------
demos/gce_demo.py | 237 ++-
libcloud/compute/drivers/gce.py | 1947 ++++++++++++++++--
.../gce/aggregated_instanceGroupManagers.json | 8 +-
.../gce/global_backendServices_web_service.json | 4 +-
.../fixtures/gce/global_instanceTemplates.json | 10 +-
.../gce/global_instanceTemplates_insert.json | 12 +
.../fixtures/gce/global_sslcertificates.json | 16 +
.../gce/global_sslcertificates_example.json | 10 +
.../gce/global_sslcertificates_post.json | 13 +
...eration_global_instanceTemplates_insert.json | 12 +
...s_operation_global_sslcertificates_post.json | 13 +
...nes_us_central1_a_instanceGroups_insert.json | 13 +
...l1_a_instanceGroups_myname_addInstances.json | 13 +
...central1_a_instanceGroups_myname_delete.json | 13 +
...a_instanceGroups_myname_removeInstances.json | 13 +
...1_a_instanceGroups_myname_setNamedPorts.json | 13 +
...s-east1_subnetworks_cf_972cf02e6ad49113.json | 11 +
...nes_us-central1-a_instanceGroupManagers.json | 4 +-
...a_instanceGroupManagers_myinstancegroup.json | 4 +-
...entral1-a_instanceGroup_myinstancegroup.json | 4 +-
...ntral1-a_instanceGroup_myinstancegroup2.json | 14 +
...b_instanceGroupManagers_myinstancegroup.json | 4 +-
...entral1-b_instanceGroup_myinstancegroup.json | 2 +-
.../zones_us-east1-b_instanceGroupManagers.json | 4 +-
...s-east1-b_instanceGroup_myinstancegroup.json | 4 +-
.../gce/zones_us_central1_a_instanceGroups.json | 29 +
...nes_us_central1_a_instanceGroups_insert.json | 13 +
...nes_us_central1_a_instanceGroups_myname.json | 12 +
...l1_a_instanceGroups_myname_addInstances.json | 13 +
...central1_a_instanceGroups_myname_delete.json | 13 +
...1_a_instanceGroups_myname_listInstances.json | 15 +
...a_instanceGroups_myname_removeInstances.json | 13 +
...1_a_instanceGroups_myname_setNamedPorts.json | 13 +
libcloud/test/compute/test_gce.py | 404 +++-
34 files changed, 2697 insertions(+), 226 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/cffd9642/demos/gce_demo.py
----------------------------------------------------------------------
diff --git a/demos/gce_demo.py b/demos/gce_demo.py
index 6322c9e..c49e5e6 100755
--- a/demos/gce_demo.py
+++ b/demos/gce_demo.py
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
# This example performs several tasks on Google Compute Platform. It can be
# run directly or can be imported into an interactive python session. This
# can also serve as live integration tests.
@@ -66,8 +65,8 @@ except ImportError:
sys.exit(1)
# Add parent dir of this file's dir to sys.path (OS-agnostically)
-sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__),
- os.path.pardir)))
+sys.path.append(
+ os.path.normpath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
from libcloud.compute.types import Provider
from libcloud.compute.providers import get_driver
@@ -92,6 +91,7 @@ DEMO_BASE_NAME = 'lct'
# Datacenter to create resources in
DATACENTER = 'us-central1-f'
+BACKUP_DATACENTER = 'us-east1-c'
# Clean up resources at the end (can be set to false in order to
# inspect resources at the end of the run). Resources will be cleaned
@@ -136,6 +136,46 @@ def get_dns_driver(gce_driver=None):
return driver
+def create_mig(gce, mig_base_name, zone, template, postfix, num_instances=2):
+ """
+ Creates MIG, sets named ports, modifies various text with 'postfix'.
+
+ :param gce: An initalized GCE driver.
+ :type gce: :class`GCENodeDriver`
+
+ :param zone: Zone to create Managed Instance Group in.
+ :type zone: :class:`GCEZone` or ``str``
+
+ :param template: Instance Template to use in creating MIG.
+ :type template: :class:`GCEInstanceTemplate`
+
+ :param postfix: string to append to mig name, etc. Example: 'east',
+ 'central'
+ :type postfix: ``str``
+
+ :param num_instances: number of instances to create in MIG. Default is 2.
+ :type num_instances: ``int``
+
+ :returns: initialized Managed Instance Group.
+ :rtype: :class:`GCEInstanceGroupManager`
+ """
+ mig_name = '%s-%s' % (mig_base_name, postfix)
+ mig = gce.ex_create_instancegroupmanager(
+ mig_name, zone, template, num_instances, base_instance_name=mig_name,
+ description='Demo for %s' % postfix)
+ display(' Managed Instance Group [%s] "%s" created' % (postfix.upper(),
+ mig.name))
+ display(' ... MIG instances created: %s' %
+ ','.join([x['name'] for x in mig.list_managed_instances()]))
+
+ # set the named_ports on the Instance Group.
+ named_ports = [{'name': '%s-http' % DEMO_BASE_NAME, 'port': 80}]
+ mig.set_named_ports(named_ports=named_ports)
+ display(' ... MIG ports set: %s' % named_ports)
+
+ return mig
+
+
def display(title, resource_list=[]):
"""
Display a list of resources.
@@ -214,8 +254,32 @@ def cleanup_only():
snapshots = gce.ex_list_snapshots()
display('Snapshots:', snapshots)
+ gfrs = gce.ex_list_forwarding_rules(global_rules=True)
+ display("Global Forwarding Rules", gfrs)
+ targetproxies = gce.ex_list_targethttpproxies()
+ display("Target HTTP Proxies", targetproxies)
+ urlmaps = gce.ex_list_urlmaps()
+ display("URLMaps", urlmaps)
+ bes = gce.ex_list_backendservices()
+ display("Backend Services", bes)
+ migs = gce.ex_list_instancegroupmanagers(zone='all')
+ display("Instance Group Managers", migs)
+ its = gce.ex_list_instancetemplates()
+ display("Instance Templates", its)
+ hcs = gce.ex_list_healthchecks()
+ display("Health Checks", hcs)
+
# == Clean up any old demo resources ==
display('Cleaning up any "%s" resources' % DEMO_BASE_NAME)
+ clean_up(gce, DEMO_BASE_NAME, None,
+ gfrs + targetproxies + urlmaps + bes + hcs + migs + its)
+
+ # == Pause to let cleanup occur and repopulate volume and node lists ==
+ if len(migs):
+ time.sleep(10)
+ all_volumes = gce.list_volumes(ex_zone='all')
+ all_nodes = gce.list_nodes(ex_zone='all')
+
clean_up(gce, DEMO_BASE_NAME, all_nodes,
all_addresses + all_volumes + firewalls + networks + snapshots)
volumes = gce.list_volumes()
@@ -260,6 +324,8 @@ def clean_up(gce, base_name, node_list=None, resource_list=None):
if resrc.name.startswith(base_name):
try:
resrc.destroy()
+ class_name = resrc.__class__.__name__
+ display(' Deleted %s (%s)' % (resrc.name, class_name))
except ResourceNotFoundError:
display(' Not found: %s (%s)' % (resrc.name,
resrc.__class__.__name__))
@@ -380,8 +446,7 @@ def main_compute():
name = '%s-subnet-node' % DEMO_BASE_NAME
node_1 = gce.create_node(name, 'g1-small', 'debian-8',
ex_disk_auto_delete=True,
- ex_network=network_custom,
- ex_subnetwork=subnet)
+ ex_network=network_custom, ex_subnetwork=subnet)
display(' Node %s created' % name)
# == Destroy instance in custom subnetwork ==
@@ -424,8 +489,7 @@ def main_compute():
},
"boot": True,
"autoDelete": True
- },
- {
+ }, {
"type": "SCRATCH",
"deviceName": '%s-gstruct-lssd' % DEMO_BASE_NAME,
"initializeParams": {
@@ -452,7 +516,7 @@ def main_compute():
display('Stopping node, setting custom size, starting node:')
name = '%s-np-node' % DEMO_BASE_NAME
gce.ex_stop_node(node_1)
- gce.ex_set_machine_type(node_1, 'custom-2-4096') # 2 vCPU, 4GB RAM
+ gce.ex_set_machine_type(node_1, 'custom-2-4096') # 2 vCPU, 4GB RAM
gce.ex_start_node(node_1)
node_1 = gce.ex_get_node(name)
display(' %s: state=%s, size=%s' % (name, node_1.extra['status'],
@@ -471,8 +535,7 @@ def main_compute():
if CLEANUP:
# == Detach the disk ==
if gce.detach_volume(volume, ex_node=node_1):
- display(' Detached %s from %s' % (volume.name,
- node_1.name))
+ display(' Detached %s from %s' % (volume.name, node_1.name))
# == Create Snapshot ==
display('Creating a snapshot from existing disk:')
@@ -499,8 +562,7 @@ def main_compute():
display(' Created %s from snapshot' % volume.name)
# Create Node with Disk
node_2 = gce.create_node(name, size, image, ex_tags=['libcloud'],
- ex_boot_disk=volume,
- ex_disk_auto_delete=False)
+ ex_boot_disk=volume, ex_disk_auto_delete=False)
display(' Node %s created with attached disk %s' % (node_2.name,
volume.name))
@@ -525,10 +587,9 @@ def main_compute():
number = MAX_NODES - 2
if number > 0:
display('Creating Multiple Nodes (%s):' % number)
- multi_nodes = gce.ex_create_multiple_nodes(base_name, size, image,
- number,
- ex_tags=['libcloud'],
- ex_disk_auto_delete=True)
+ multi_nodes = gce.ex_create_multiple_nodes(
+ base_name, size, image, number, ex_tags=['libcloud'],
+ ex_disk_auto_delete=True)
for node in multi_nodes:
display(' Node %s created' % node.name)
@@ -542,8 +603,7 @@ def main_compute():
# == Create a Firewall ==
display('Creating a Firewall:')
name = '%s-firewall' % DEMO_BASE_NAME
- allowed = [{'IPProtocol': 'tcp',
- 'ports': ['3141']}]
+ allowed = [{'IPProtocol': 'tcp', 'ports': ['3141']}]
firewall_1 = gce.ex_create_firewall(name, allowed, network=network_1,
source_tags=['libcloud'])
display(' Firewall %s created' % firewall_1.name)
@@ -629,20 +689,16 @@ def main_load_balancer():
size = gce.ex_get_size('n1-standard-1')
number = 3
display('Creating %d nodes' % number)
- metadata = {'items': [{'key': 'startup-script',
- 'value': startup_script}]}
- lb_nodes = gce.ex_create_multiple_nodes(base_name, size, image,
- number, ex_tags=[tag],
- ex_metadata=metadata,
- ex_disk_auto_delete=True,
- ignore_errors=False)
+ metadata = {'items': [{'key': 'startup-script', 'value': startup_script}]}
+ lb_nodes = gce.ex_create_multiple_nodes(
+ base_name, size, image, number, ex_tags=[tag], ex_metadata=metadata,
+ ex_disk_auto_delete=True, ignore_errors=False)
display('Created Nodes', lb_nodes)
# == Create a Firewall for instances ==
display('Creating a Firewall')
name = '%s-firewall' % DEMO_BASE_NAME
- allowed = [{'IPProtocol': 'tcp',
- 'ports': ['80']}]
+ allowed = [{'IPProtocol': 'tcp', 'ports': ['80']}]
firewall = gce.ex_create_firewall(name, allowed, target_tags=[tag])
display(' Firewall %s created' % firewall.name)
@@ -652,10 +708,9 @@ def main_load_balancer():
# These are all the default values, but listed here as an example. To
# create a healthcheck with the defaults, only name is required.
- hc = gcelb.ex_create_healthcheck(name, host=None, path='/', port='80',
- interval=5, timeout=5,
- unhealthy_threshold=2,
- healthy_threshold=2)
+ hc = gcelb.ex_create_healthcheck(
+ name, host=None, path='/', port='80', interval=5, timeout=5,
+ unhealthy_threshold=2, healthy_threshold=2)
display('Healthcheck %s created' % hc.name)
# == Create Load Balancer ==
@@ -739,6 +794,114 @@ def main_load_balancer():
display('Total runtime: %s' % str(end_time - start_time))
+# ==== BACKEND SERVICE LOAD BALANCER CODE STARTS HERE ====
+def main_backend_service():
+ start_time = datetime.datetime.now()
+ display('Backend Service w/Global Forwarding Rule demo/test start time: %s'
+ % str(start_time))
+ gce = get_gce_driver()
+ # Get project info and print name
+ project = gce.ex_get_project()
+ display('Project: %s' % project.name)
+
+ # Based on the instructions at:
+ # https://cloud.google.com/compute/docs/load-balancing/http/#overview
+
+ zone_central = DATACENTER
+ zone_east = BACKUP_DATACENTER
+ it_name = '%s-instancetemplate' % DEMO_BASE_NAME
+ mig_name = '%s-mig' % DEMO_BASE_NAME
+ hc_name = '%s-healthcheck' % DEMO_BASE_NAME
+ bes_name = '%s-bes' % DEMO_BASE_NAME
+ urlmap_name = '%s-urlmap' % DEMO_BASE_NAME
+ targethttpproxy_name = '%s-httptargetproxy' % DEMO_BASE_NAME
+ address_name = '%s-address' % DEMO_BASE_NAME
+ gfr_name = '%s-gfr' % DEMO_BASE_NAME
+ firewall_name = '%s-firewall' % DEMO_BASE_NAME
+
+ startup_script = ('apt-get -y update && '
+ 'apt-get -y install apache2 && '
+ 'echo "$(hostname)" > /var/www/html/index.html')
+ tag = '%s-mig-www' % DEMO_BASE_NAME
+ metadata = {'items': [{'key': 'startup-script', 'value': startup_script}]}
+
+ mig_central = None
+ mig_east = None
+ bes = None
+ urlmap = None
+ tp = None
+ address = None
+ gfr = None
+ firewall = None
+
+ display('Create a BackendService')
+ # == Create an Instance Template ==
+ it = gce.ex_create_instancetemplate(it_name, size='n1-standard-1',
+ image='debian-8', network='default',
+ metadata=metadata, tags=[tag])
+ display(' InstanceTemplate "%s" created' % it.name)
+
+ # == Create a MIG ==
+ mig_central = create_mig(gce, mig_name, zone_central, it, 'central')
+ mig_east = create_mig(gce, mig_name, zone_east, it, 'east')
+
+ # == Create a Health Check ==
+ hc = gce.ex_create_healthcheck(hc_name, host=None, path='/', port='80',
+ interval=30, timeout=10,
+ unhealthy_threshold=10, healthy_threshold=1)
+ display(' Healthcheck %s created' % hc.name)
+
+ # == Create a Backend Service ==
+ be_central = gce.ex_create_backend(
+ instance_group=mig_central.instance_group)
+ be_east = gce.ex_create_backend(instance_group=mig_east.instance_group)
+ bes = gce.ex_create_backendservice(
+ bes_name, [hc], backends=[be_central, be_east], port_name='%s-http' %
+ DEMO_BASE_NAME, protocol='HTTP', description='%s bes desc' %
+ DEMO_BASE_NAME, timeout_sec=60, enable_cdn=False)
+ display(' Backend Service "%s" created' % bes.name)
+
+ # == Create a URLMap ==
+ urlmap = gce.ex_create_urlmap(urlmap_name, default_service=bes)
+ display(' URLMap "%s" created' % urlmap.name)
+
+ # == Create a Target (HTTP) Proxy ==
+ tp = gce.ex_create_targethttpproxy(targethttpproxy_name, urlmap)
+ display(' TargetProxy "%s" created' % tp.name)
+
+ # == Create a Static Address ==
+ address = gce.ex_create_address(address_name, region='global')
+ display(' Address "%s" created with IP "%s"' % (address.name,
+ address.address))
+ # == Create a Global Forwarding Rule ==
+ gfr = gce.ex_create_forwarding_rule(
+ gfr_name, target=tp, address=address, port_range='80',
+ description='%s libcloud forwarding rule http test' % DEMO_BASE_NAME,
+ global_rule=True)
+ display(' Global Forwarding Rule "%s" created' % (gfr.name))
+
+ # == Create a Firewall for instances ==
+ allowed = [{'IPProtocol': 'tcp', 'ports': ['80']}]
+ firewall = gce.ex_create_firewall(firewall_name, allowed,
+ target_tags=[tag])
+ display(' Firewall %s created' % firewall.name)
+
+ # TODO(supertom): launch instances to demostrate that it works
+ # take backends out of service. Adding in this functionality
+ # will also add 10-15 minutes to the demo.
+ # display("Sleeping for 10 minutes, starting at %s" %
+ # str(datetime.datetime.now()))
+ # time.sleep(600)
+
+ if CLEANUP:
+ display('Cleaning up %s resources created' % DEMO_BASE_NAME)
+ clean_up(gce, DEMO_BASE_NAME, None,
+ resource_list=[firewall, gfr, address, tp, urlmap, bes, hc,
+ mig_central, mig_east, it])
+ end_time = datetime.datetime.now()
+ display('Total runtime: %s' % str(end_time - start_time))
+
+
# ==== GOOGLE DNS CODE STARTS HERE ====
def main_dns():
start_time = datetime.datetime.now()
@@ -768,17 +931,19 @@ def main_dns():
end_time = datetime.datetime.now()
display('Total runtime: %s' % str(end_time - start_time))
+
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Google Cloud Platform Demo / Live Test Script')
- parser.add_argument("--compute",
- help="perform compute demo / live tests",
+ parser.add_argument("--compute", help="perform compute demo / live tests",
dest="compute", action="store_true")
parser.add_argument("--load-balancer",
help="perform load-balancer demo / live tests",
dest="lb", action="store_true")
- parser.add_argument("--dns",
- help="perform DNS demo / live tests",
+ parser.add_argument("--backend-service",
+ help="perform backend-service demo / live tests",
+ dest="bes", action="store_true")
+ parser.add_argument("--dns", help="perform DNS demo / live tests",
dest="dns", action="store_true")
parser.add_argument("--cleanup-only",
help="perform clean-up (skips all tests)",
@@ -794,3 +959,5 @@ if __name__ == '__main__':
main_load_balancer()
if cl_args.dns:
main_dns()
+ if cl_args.bes:
+ main_backend_service()