The code imports functions from a Core
module and defines several functions to manage Google Cloud resources, including creating backend buckets and SSL certificates, and listing various Google Cloud items. However, the functions are not fully implemented and contain TODO comments, suggesting that the code is a partial implementation of a larger application.
npm run import -- "add a google bucket web map"
var importer = require('../Core');
var authorizeGoogle = importer.import("authorize google service");
var waitForOperation = importer.import("wait google cloud operation");
var uuid = require('uuid/v1');
var {
listBackendBuckets,
listTargetProxies,
listGlobalForwards,
listUrlMaps,
listSslCertificates
} = importer.import("list google bucket url map");
var createBucket = importer.import("create storage bucket");
function safeName(name) {
return name.replace(/[^a-z0-9\-]/ig, '-').substr(0, 50).toLowerCase();
}
function insertBackendBucket(project, bucketName) {
// TODO: check for creation of bucket here?
var name = 'bb-' + uuid().substr(0, 5) + '-' + safeName(bucketName);
return createBucket(project, bucketName)
.then(() => listBackendBuckets(project, bucketName))
.then(buckets => {
if(Object.keys(buckets).length > 0) {
name = Object.keys(buckets)[0];
console.log(`Bucket ${bucketName} already mapped`);
return Promise.resolve(Object.keys(buckets)[0]);
}
console.log(`Creating a backend for ${bucketName}`);
return authorizeGoogle()
.then(client => client.request({
method: 'POST',
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/backendBuckets`,
data: {
name: name,
bucketName: bucketName,
enableCdn: false,
kind: 'compute#backendBucket'
}
}))
.then(backend => {
return waitForOperation(backend.data.selfLink);
})
})
.then(() => name);
}
function addSslCertificate(project, bucketName) {
return authorizeGoogle()
.then(client => client.request({
method: 'POST',
url: `https://www.googleapis.com/compute/beta/projects/${project}/global/sslCertificates`,
data: {
name: 'cert-' + safeName(bucketName),
description: bucketName,
managed: {domains: [bucketName]},
type: 'MANAGED'
// sslPolicy: 'https://www.googleapis.com/compute/v1/projects/spahaha-ea443/global/sslPolicies/my-ssl-policy'
}
}))
.then(ssl => {
return waitForOperation(ssl.data.selfLink);
})
.then(() => 'cert-' + safeName(bucketName))
}
function insertSslCertificate(project, bucketName) {
return listSslCertificates(project, 'cert-' + safeName(bucketName))
.then(ssl => {
if(Object.keys(ssl).length > 0) {
console.log(`SSL ${bucketName} already exists`);
return Promise.resolve(Object.keys(ssl)[0]);
}
console.log(`Creating an SSL cert for ${bucketName}`);
return addSslCertificate(project, bucketName);
})
}
function addTargetHttpsProxy(project, urlMap, bucketName) {
// TODO: get SSL cert first because it's require by proxy
var sslCertificate;
var proxyName = 'thp-' + uuid().substr(0, 5) + '-' + safeName(bucketName);
return insertSslCertificate(project, bucketName)
.then(ssl => {
sslCertificate = ssl;
})
.then(() => authorizeGoogle())
.then(client => client.request({
method: 'POST',
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/targetHttpsProxies`,
data: {
name: proxyName,
urlMap: `https://www.googleapis.com/compute/v1/projects/${project}/global/urlMaps/${urlMap}`,
sslCertificates: [
`https://www.googleapis.com/compute/v1/projects/${project}/global/sslCertificates/${sslCertificate}`
],
// sslPolicy: 'https://www.googleapis.com/compute/v1/projects/spahaha-ea443/global/sslPolicies/my-ssl-policy'
}
}))
.then(proxy => {
return waitForOperation(proxy.data.selfLink);
})
.then(() => proxyName)
}
function insertTargetHttpsProxy(project, urlMap, bucketName) {
// check for a proxy with an sslCert matching our project name
return listTargetProxies(project)
.then(proxies => {
var matches = Object.keys(proxies)
.filter(k => proxies[k]
.filter(cert => cert.includes(`https://www.googleapis.com/compute/v1/projects/${project}/global/sslCertificates/cert-${safeName(bucketName)}`)).length > 0);
// TODO: is using sheet-to-web host, just add the certificate to existing proxy
// support for SNI? https://www.ietf.org/rfc/rfc4366.txt
if(matches.length > 0) {
console.log(`Proxy ${bucketName} already exists`);
return Promise.resolve(Object.keys(proxies)[0]);
}
console.log(`Creating a proxy for ${bucketName}`);
return addTargetHttpsProxy(project, urlMap, bucketName);
})
}
function addGlobalForward(project, ip, urlMap, bucketName, targetHttpsProxy) {
var name = 'gfr-' + uuid().substr(0, 5) + '-' + safeName(urlMap)
return authorizeGoogle()
.then(client => client.request({
method: 'POST',
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/forwardingRules`,
data: {
name: name,
IPAddress: `https://www.googleapis.com/compute/v1/projects/${project}/global/addresses/${ip}`,
IPProtocol: 'TCP',
portRange: '443-443',
target: `https://www.googleapis.com/compute/v1/projects/${project}/global/targetHttpsProxies/${targetHttpsProxy}`,
loadBalancingScheme: 'EXTERNAL',
networkTier: 'PREMIUM'
}
}))
.then(rule => {
return waitForOperation(rule.data.selfLink);
})
.then(() => name);
}
function insertGlobalForward(project, ip, urlMap, bucketName) {
// get proxy first because it's require by forwardRule
var targetHttpsProxy;
return insertTargetHttpsProxy(project, urlMap, bucketName)
.then(proxy => (targetHttpsProxy = proxy))
.then(() => listGlobalForwards(project, targetHttpsProxy))
.then(forwards => {
if(Object.keys(forwards).length > 0) {
console.log(`Forward for ${bucketName} already exists`);
return Promise.resolve(Object.keys(forwards)[0]);
}
console.log(`Creating a forward for ${bucketName}`);
return addGlobalForward(project, ip, urlMap, bucketName, targetHttpsProxy);
})
}
function updateUrlMap(project, urlMap, bucketName) {
return listUrlMaps(project, urlMap)
// add a global forward if the ip isn't already set up
.then(maps => {
if(typeof maps[urlMap] == 'undefined') {
// TODO: create the map
throw new Error('Implement url map create');
}
if(maps[urlMap].hostRules.filter(hr => hr.hosts.filter(h => h == bucketName).length > 0).length > 0) {
console.log(`Map host rule ${bucketName} already exists`);
return Promise.resolve(urlMap);
}
console.log(`Map ${urlMap} already exists, adding host rule`);
var defaultService;
var pathMatcherName = 'pm-' + uuid().substr(0, 5) + '-' + safeName(bucketName);
return insertBackendBucket(project, bucketName)
.then(bn => (defaultService = bn))
.then(() => authorizeGoogle())
.then(client => client.request({
method: 'PATCH',
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/urlMaps/${urlMap}`,
data: {
fingerprint: maps[urlMap].fingerprint,
hostRules: maps[urlMap].hostRules.concat([{
hosts: [bucketName],
pathMatcher: pathMatcherName
}]),
pathMatchers: maps[urlMap].pathMatchers.concat([{
name: pathMatcherName,
defaultService: `https://www.googleapis.com/compute/v1/projects/${project}/global/backendBuckets/${defaultService}`,
pathRules: ['/', '/*']
}]),
}
}))
.then(path => {
return waitForOperation(path.data.selfLink);
})
.then(map => pathMatcherName)
});
}
module.exports = {
insertBackendBucket,
insertGlobalForward,
updateUrlMap
};
```javascript
const { google } = require('googleapis');
const { v1 } = google.apis;
const { v1 as storage } = google.storage;
const { v1 as compute } = google.compute;
const uuid = require('uuid/v4');
const safeName = (name) => {
return name.replace(/[^a-z0-9\-]/ig, '-').substr(0, 50).toLowerCase();
};
const getGoogleClient = async () => {
const auth = new google.auth.GoogleAuth({
// Use the application default credentials
// If you have a private key file, use the following instead
// credentials: JSON.parse(File.read('path/to/key.json')),
});
const client = await auth.getClient();
return client;
};
const createBucket = async (project, bucketName) => {
const storageClient = new storage.v1.StorageClient();
const bucketRequest = {
parent: `projects/${project}`,
body: {
name: bucketName,
},
};
const [response] = await storageClient.buckets.create(bucketRequest);
return response.name;
};
const getBackendBuckets = async (project, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(bucketName)} AND name~=${safeName(bucketName)}`,
};
const [response] = await computeClient.globalBackendBuckets.list(request);
return response/backendBuckets;
};
const getBackendBucket = async (project, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(bucketName)} AND name~=${safeName(bucketName)}`,
};
const response = await computeClient.globalBackendBuckets.list(request);
const buckets = response.backendBuckets;
if (buckets.length > 0) {
return buckets[0].name;
} else {
return null;
}
};
const createBackendBucket = async (project, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const backendRequest = {
parent: `projects/${project}`,
body: {
name: `bb-${uuid().substr(0, 5)}-${safeName(bucketName)}`,
bucketName,
enableCdn: false,
kind: 'compute#backendBucket',
},
};
const [response] = await computeClient.globalBackendBuckets.insert(backendRequest);
return response.name;
};
const insertBackendBucket = async (project, bucketName) => {
const name = await getBackendBucket(project, bucketName) || await createBackendBucket(project, bucketName);
return name;
};
const createSslCertificate = async (project, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const sslRequest = {
parent: `projects/${project}`,
body: {
name: `cert-${safeName(bucketName)}`,
description: bucketName,
managed: { domains: [bucketName] },
type: 'MANAGED',
},
};
const [response] = await computeClient.globalSslCertificates.insert(sslRequest);
return response.name;
};
const getSslCertificates = async (project, name) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(name)}`,
};
const response = await computeClient.globalSslCertificates.list(request);
return response.sslCertificates;
};
const getSslCertificate = async (project, name) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(name)}`,
};
const response = await computeClient.globalSslCertificates.list(request);
const certificates = response.sslCertificates;
if (certificates.length > 0) {
return certificates[0].name;
} else {
return null;
}
};
const insertSslCertificate = async (project, bucketName) => {
const name = await getSslCertificate(project, bucketName) || await createSslCertificate(project, bucketName);
return name;
};
const createTargetHttpsProxy = async (project, urlMap, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const proxyRequest = {
parent: `projects/${project}`,
body: {
name: `thp-${uuid().substr(0, 5)}-${safeName(bucketName)}`,
urlMap: `https://www.googleapis.com/compute/v1/projects/${project}/global/urlMaps/${urlMap}`,
sslCertificates: [`https://www.googleapis.com/compute/v1/projects/${project}/global/sslCertificates/${await insertSslCertificate(project, bucketName)}`],
},
};
const [response] = await computeClient.globalTargetHttpsProxies.insert(proxyRequest);
return response.name;
};
const getTargetHttpsProxies = async (project) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(project)}`,
};
const response = await computeClient.globalTargetHttpsProxies.list(request);
return response.targetHttpsProxies;
};
const getTargetHttpsProxy = async (project, name) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(name)}`,
};
const response = await computeClient.globalTargetHttpsProxies.list(request);
const proxies = response.targetHttpsProxies;
if (proxies.length > 0) {
return proxies[0].name;
} else {
return null;
}
};
const insertTargetHttpsProxy = async (project, urlMap, bucketName) => {
const name = await getTargetHttpsProxy(project, bucketName) || await createTargetHttpsProxy(project, urlMap, bucketName);
return name;
};
const createGlobalForward = async (project, ip, urlMap, bucketName, targetHttpsProxy) => {
const computeClient = new compute.v1.ComputeClient();
const forwardRequest = {
parent: `projects/${project}`,
body: {
name: `gfr-${uuid().substr(0, 5)}-${safeName(bucketName)}`,
IPAddress: `https://www.googleapis.com/compute/v1/projects/${project}/global/addresses/${ip}`,
IPProtocol: 'TCP',
portRange: '443-443',
target: `https://www.googleapis.com/compute/v1/projects/${project}/global/targetHttpsProxies/${targetHttpsProxy}`,
loadBalancingScheme: 'EXTERNAL',
networkTier: 'PREMIUM',
},
};
const [response] = await computeClient.globalForwardingRules.insert(forwardRequest);
return response.name;
};
const getGlobalForwards = async (project, targetHttpsProxy) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(targetHttpsProxy)}`,
};
const response = await computeClient.globalForwardingRules.list(request);
return response.forwardingRules;
};
const getGlobalForward = async (project, targetHttpsProxy) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(targetHttpsProxy)}`,
};
const response = await computeClient.globalForwardingRules.list(request);
const forwards = response.forwardingRules;
if (forwards.length > 0) {
return forwards[0].name;
} else {
return null;
}
};
const insertGlobalForward = async (project, ip, urlMap, bucketName) => {
const targetHttpsProxy = await insertTargetHttpsProxy(project, urlMap, bucketName);
const name = await getGlobalForward(project, targetHttpsProxy) || await createGlobalForward(project, ip, urlMap, bucketName, targetHttpsProxy);
return name;
};
const getGlobalUrlMaps = async (project) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(project)}`,
};
const response = await computeClient.globalUrlMaps.list(request);
return response.urlMaps;
};
const getGlobalUrlMap = async (project, name) => {
const computeClient = new compute.v1.ComputeClient();
const request = {
filter: `labels.service-internal~=${safeName(name)}`,
};
const response = await computeClient.globalUrlMaps.list(request);
const maps = response.urlMaps;
if (maps.length > 0) {
return maps[0].name;
} else {
return null;
}
};
const insertUrlMap = async (project, urlMap, bucketName) => {
const computeClient = new compute.v1.ComputeClient();
const getMapRequest = {
name: urlMap,
};
const [response] = await computeClient.globalUrlMaps.get(getMapRequest);
if (response.hostRules.some((hr) => hr.hosts.includes(bucketName))) {
console.log(`Map host rule ${bucketName} already exists`);
return Promise.resolve(urlMap);
}
const createBackendBucketRequest = {
parent: `projects/${project}`,
body: {
name: `bb-${uuid().substr(0, 5)}-${safeName(bucketName)}`,
bucketName,
enableCdn: false,
kind: 'compute#backendBucket',
},
};
const [backendResponse] = await computeClient.globalBackendBuckets.insert(createBackendBucketRequest);
const backendName = backendResponse.name;
const updateUrlMapRequest = {
url: urlMap,
body: {
fingerprint: response.fingerprint,
hostRules: response.hostRules.concat([
{
hosts: [bucketName],
pathMatcher: `${safeName(bucketName)}-matcher`,
},
]),
pathMatchers: response.pathMatchers.concat([
{
name: `${safeName(bucketName)}-matcher`,
defaultService: `https://www.googleapis.com/compute/v1/projects/${project}/global/backendBuckets/${backendName}`,
pathRules: ['/'],
},
]),
},
};
const [updatedResponse] = await computeClient.globalUrlMaps.patch(updateUrlMapRequest);
return updatedResponse.name;
};
const updateUrlMap = async (project, urlMap, bucketName) => {
const name = await getGlobalUrlMap(project, urlMap) || await insertUrlMap(project, urlMap, bucketName);
return name;
};
module.exports = {
insertBackendBucket,
insertGlobalForward,
updateUrlMap,
};
```
Code Breakdown
Core
module using require
and import
statements.authorizeGoogle
servicewaitForOperation
in Google Clouduuid
for generating unique IDslistBackendBuckets
, listTargetProxies
, listGlobalForwards
, listUrlMaps
, and listSslCertificates
for listing Google Cloud itemscreateBucket
for creating a storage bucketsafeName(name)
name
as input and returns a modified version:
insertBackendBucket(project, bucketName)
project
and bucketName
.uuid
and safeName
.createBucket
.authorizeGoogle
and waitForOperation
.addSslCertificate(project, bucketName)
project
and bucketName
.authorizeGoogle
.POST
method on the URL for SSL certificates in Google Compute.Promise
and then
method to handle asynchronous operations.