Skip to content

Commit

Permalink
feat: resource autodetection for cloud run (#1024)
Browse files Browse the repository at this point in the history
* feat: resource autodetection for cloud run

* fix: add location to cloud run resource label

* test: add unit test for getCloudRunDescriptor

* test: fix environments.cloudrun unit test

* feat: add cloud run to detectServiceContext

* chore: update env-tests-logging submodule to latest
  • Loading branch information
freelerobot authored Apr 5, 2021
1 parent f32da13 commit 08c4404
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 6 deletions.
2 changes: 1 addition & 1 deletion env-tests-logging
38 changes: 34 additions & 4 deletions src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ export function getCloudFunctionDescriptor() {
};
}

/**
* Create a descriptor for Cloud Run.
*
* @returns {object}
*/
export async function getCloudRunDescriptor() {
const qualifiedZone = await gcpMetadata.instance('zone');
const location = zoneFromQualifiedZone(qualifiedZone);
return {
type: 'cloud_run_revision',
labels: {
location,
service_name: process.env.K_SERVICE,
revision_name: process.env.K_REVISION,
configuration_name: process.env.K_CONFIGURATION,
},
};
}

/**
* Create a descriptor for Google App Engine.
*
Expand Down Expand Up @@ -146,7 +165,6 @@ export function getGlobalDescriptor() {
*/
export async function getDefaultResource(auth: GoogleAuth) {
const env = await auth.getEnv();

switch (env) {
case GCPEnv.KUBERNETES_ENGINE:
return getGKEDescriptor().catch(() => getGlobalDescriptor());
Expand All @@ -155,9 +173,14 @@ export async function getDefaultResource(auth: GoogleAuth) {
case GCPEnv.CLOUD_FUNCTIONS:
return getCloudFunctionDescriptor();
case GCPEnv.COMPUTE_ENGINE:
// Test for compute engine should be done after all the rest -
// everything runs on top of compute engine.
return getGCEDescriptor().catch(() => getGlobalDescriptor());
// Google Cloud Run
if (process.env.K_CONFIGURATION) {
return getCloudRunDescriptor().catch(() => getGlobalDescriptor());
} else {
// Test for compute engine should be done after all the rest -
// everything runs on top of compute engine.
return getGCEDescriptor().catch(() => getGlobalDescriptor());
}
default:
return getGlobalDescriptor();
}
Expand Down Expand Up @@ -190,6 +213,13 @@ export async function detectServiceContext(
// name from within the pod.
case GCPEnv.KUBERNETES_ENGINE:
case GCPEnv.COMPUTE_ENGINE:
// Google Cloud Run
if (process.env.K_CONFIGURATION) {
return {
service: process.env.K_SERVICE,
};
}
return null;
default:
return null;
}
Expand Down
111 changes: 110 additions & 1 deletion test/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ describe('metadata', () => {
let AUTH;
const ENV_CACHED = extend({}, process.env);

const INITIAL_ENV: {[key: string]: string | undefined} = {};

before(() => {
metadata = proxyquire('../src/metadata', {
'gcp-metadata': fakeGcpMetadata,
Expand Down Expand Up @@ -101,7 +103,6 @@ describe('metadata', () => {
'K_SERVICE',
'GOOGLE_CLOUD_REGION',
];
const INITIAL_ENV: {[key: string]: string | undefined} = {};

before(() => {
for (const key of TARGET_KEYS) {
Expand Down Expand Up @@ -152,6 +153,56 @@ describe('metadata', () => {
});
});

describe('getCloudRunDescriptor', () => {
const K_SERVICE = 'hello-world';
const K_REVISION = 'hello-world.1';
const K_CONFIGURATION = 'hello-world';

const TARGET_KEYS = ['K_SERVICE', 'K_REVISION', 'K_CONFIGURATION'];

before(() => {
for (const key of TARGET_KEYS) {
INITIAL_ENV[key] = process.env[key];
}
});

after(() => {
for (const key of TARGET_KEYS) {
const val = INITIAL_ENV[key];
if (val === undefined) {
delete process.env[key];
} else {
process.env[key] = val;
}
}
});

beforeEach(() => {
for (const key of TARGET_KEYS) {
delete process.env[key];
}
process.env.K_SERVICE = K_SERVICE;
process.env.K_REVISION = K_REVISION;
process.env.K_CONFIGURATION = K_CONFIGURATION;
});

it('should return the correct descriptor', async () => {
const ZONE_ID = 'cyrodiil-anvil-2';
const ZONE_FULL = `projects/fake-project/zones/${ZONE_ID}`;
instanceOverride = {path: 'zone', successArg: ZONE_FULL};
const descriptor = await metadata.getCloudRunDescriptor();
assert.deepStrictEqual(descriptor, {
type: 'cloud_run_revision',
labels: {
service_name: K_SERVICE,
revision_name: K_REVISION,
configuration_name: K_CONFIGURATION,
location: ZONE_ID,
},
});
});
});

describe('getGAEDescriptor', () => {
const GAE_MODULE_NAME = 'gae-module-name';
const GAE_SERVICE = 'gae-service';
Expand Down Expand Up @@ -302,6 +353,47 @@ describe('metadata', () => {
});
});

describe('cloud run', () => {
after(() => {
delete process.env['K_CONFIGURATION'];
delete process.env['K_REVISION'];
delete process.env['K_SERVICE'];
});

it('should return correct descriptor', async () => {
const K_SERVICE = 'hello-world';
const K_CONFIGURATION = 'hello-world';
const K_REVISION = 'hello-world.1';
const ZONE_ID = 'cyrodiil-anvil-2';
const ZONE_FULL = `projects/fake-project/zones/${ZONE_ID}`;
process.env.K_SERVICE = K_SERVICE;
process.env.K_REVISION = K_REVISION;
process.env.K_CONFIGURATION = K_CONFIGURATION;
instanceOverride = [
{
path: 'zone',
successArg: ZONE_FULL,
},
];
const fakeAuth = {
async getEnv() {
return GCPEnv.COMPUTE_ENGINE;
},
};

const defaultResource = await metadata.getDefaultResource(fakeAuth);
assert.deepStrictEqual(defaultResource, {
type: 'cloud_run_revision',
labels: {
service_name: K_SERVICE,
revision_name: K_REVISION,
configuration_name: K_CONFIGURATION,
location: ZONE_ID,
},
});
});
});

describe('compute engine', () => {
it('should return correct descriptor', async () => {
const INSTANCE_ID = 1234567;
Expand Down Expand Up @@ -458,6 +550,23 @@ describe('metadata', () => {
assert.deepStrictEqual(sc1, {service: FUNCTION_NAME});
});

it('should return the correct descriptor for Cloud Run', async () => {
process.env.K_CONFIGURATION = 'hello-world';
const SERVICE_NAME = (process.env.K_SERVICE = 'hello-world');

const fakeAuth = {
async getEnv() {
return GCPEnv.COMPUTE_ENGINE;
},
};

const sc1 = await metadata.detectServiceContext(fakeAuth);
assert.deepStrictEqual(sc1, {service: SERVICE_NAME});

delete process.env['K_CONFIGURATION'];
delete process.env['K_SERVICE'];
});

it('should return null on GKE', async () => {
const fakeAuth = {
async getEnv() {
Expand Down

0 comments on commit 08c4404

Please sign in to comment.