Skip to content

Commit

Permalink
GCP utils (#16)
Browse files Browse the repository at this point in the history
### What changes were proposed in this pull request?
Introduces a new `GCPUtils` class that provides a unified interface for interacting with various Google Cloud Platform services:
- Secret Manager operations for managing secrets
- Cloud Storage methods for file upload/download
- Cloud Scheduler functionality for job creation
- Cloud Run service deployment capabilities
- Cloud SQL database management
- Helper methods for resource verification

### Why are the changes needed?
To centralize and standardize GCP service interactions within the application, reducing code duplication and providing a consistent interface for common cloud operations. This utility class will make it easier to manage cloud resources and perform common GCP operations throughout the application.

### Does this PR introduce _any_ user-facing change?
No

### How was this patch tested?
Each GCP service method includes error handling and follows GCP best practices. Integration tests should be added to verify interactions with each cloud service in isolation.
  • Loading branch information
JerryPan2718 authored Jan 11, 2025
1 parent 151f0a1 commit dd74e3a
Show file tree
Hide file tree
Showing 3 changed files with 1,672 additions and 110 deletions.
158 changes: 158 additions & 0 deletions core/utils/gcpUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { SecretManagerServiceClient } from "@google-cloud/secret-manager";
import { CloudSchedulerClient } from "@google-cloud/scheduler";
import { Storage } from "@google-cloud/storage";
import { CloudRunClient } from "@google-cloud/run";
import { Compute } from "@google-cloud/compute";

export class GCPUtils {
private secretManager: SecretManagerServiceClient;
private scheduler: CloudSchedulerClient;
private storage: Storage;
private cloudRun: CloudRunClient;
private compute: Compute;
private projectId: string;

constructor(projectId: string) {
this.projectId = projectId;
this.secretManager = new SecretManagerServiceClient();
this.scheduler = new CloudSchedulerClient();
this.storage = new Storage();
this.cloudRun = new CloudRunClient();
this.compute = new Compute();
}

// Secret Manager Methods
async getSecret(secretName: string, version = "latest"): Promise<string> {
try {
const name = `projects/${this.projectId}/secrets/${secretName}/versions/${version}`;
const [response] = await this.secretManager.accessSecretVersion({ name });
return response.payload?.data?.toString() || "";
} catch (error) {
throw new Error(`Failed to get secret: ${error}`);
}
}

async createSecret(secretId: string, payload: string): Promise<void> {
try {
const parent = `projects/${this.projectId}`;
await this.secretManager.createSecret({
parent,
secretId,
secret: {
replication: {
automatic: {},
},
},
});
await this.secretManager.addSecretVersion({
parent: `projects/${this.projectId}/secrets/${secretId}`,
payload: {
data: Buffer.from(payload, "utf8"),
},
});
} catch (error) {
throw new Error(`Failed to create secret: ${error}`);
}
}

// Cloud Storage Methods
async uploadFile(
bucketName: string,
filePath: string,
destination: string,
): Promise<void> {
try {
const bucket = this.storage.bucket(bucketName);
await bucket.upload(filePath, {
destination,
});
} catch (error) {
throw new Error(`Failed to upload file: ${error}`);
}
}

async downloadFile(
bucketName: string,
fileName: string,
destination: string,
): Promise<void> {
try {
const bucket = this.storage.bucket(bucketName);
await bucket.file(fileName).download({
destination,
});
} catch (error) {
throw new Error(`Failed to download file: ${error}`);
}
}

// Cloud Scheduler Methods
async createJob(
jobName: string,
schedule: string,
targetUrl: string,
): Promise<void> {
try {
const parent = `projects/${this.projectId}/locations/us-central1`;
await this.scheduler.createJob({
parent,
job: {
name: `${parent}/jobs/${jobName}`,
httpTarget: {
uri: targetUrl,
httpMethod: "POST",
},
schedule,
timeZone: "UTC",
},
});
} catch (error) {
throw new Error(`Failed to create job: ${error}`);
}
}

// Cloud Run Methods
async deployService(
serviceName: string,
image: string,
envVars: Record<string, string> = {},
): Promise<void> {
try {
const parent = `projects/${this.projectId}/locations/us-central1`;
await this.cloudRun.createService({
parent,
service: {
name: `${parent}/services/${serviceName}`,
template: {
containers: [
{
image,
env: Object.entries(envVars).map(([key, value]) => ({
name: key,
value,
})),
},
],
},
},
});
} catch (error) {
throw new Error(`Failed to deploy service: ${error}`);
}
}

// Helper Methods
async checkResourceExists(resourcePath: string): Promise<boolean> {
try {
await this.secretManager.getProjectParent({
name: resourcePath,
});
return true;
} catch {
return false;
}
}
}

// Export a singleton instance
export const gcpUtils = new GCPUtils(process.env.GOOGLE_CLOUD_PROJECT || "");
Loading

0 comments on commit dd74e3a

Please sign in to comment.