Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of deploying a Go project to fargate. #7673

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ use_repo(
go_deps,
"co_honnef_go_tools",
"com_github_a_h_generate",
"com_github_aws_aws_lambda_go",
"com_github_bazelbuild_bazel_watcher",
"com_github_bazelbuild_buildtools",
"com_github_go_delve_delve",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ toolchain go1.23.4

require (
github.com/a-h/generate v0.0.0-20220105161013-96c14dfdfb60
github.com/aws/aws-lambda-go v1.47.0
github.com/bazelbuild/bazel-gazelle v0.40.0
github.com/bazelbuild/bazel-watcher v0.25.3
github.com/bazelbuild/buildtools v0.0.0-20240918101019-be1c24cc9a44
Expand Down
16 changes: 2 additions & 14 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ts/pulumi/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ts_project(
"//ts/pulumi/lulu.computer:pulumi_ts",
"//ts/pulumi/pleaseintroducemetoyour.dog:ts",
"//ts/pulumi/shadwell.im",
"//ts/pulumi/zemn.me/hello_world:ts",
],
)

Expand Down
81 changes: 73 additions & 8 deletions ts/pulumi/lib/oci/oci_image.tmpl.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,94 @@
import { createHash } from 'node:crypto';
import { mkdir, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path, { resolve } from 'node:path';

import { local } from '@pulumi/command';
import { ComponentResource, ComponentResourceOptions, Input, output } from "@pulumi/pulumi";
import { all, ComponentResource, ComponentResourceOptions, Input, interpolate, Output, output } from "@pulumi/pulumi";


export interface Args {
repository: Input<string>
token?: Input<string | undefined>
}

const imgAuthConfigFilename = "config.json";

export async function createPodmanAuthFile(
token: string,
registry: string
): Promise<string> {
// Encode credentials

// Build the auth.json structure
const authData = {
auths: {
[`https://${registry}`]: {
auth: token
},
// i dont know which is right so im just trying both
[`${registry}`]: {
auth: token
},
},
};

const fileContent = JSON.stringify(authData)

const hash = createHash('sha256').update(fileContent).digest('hex');

// Generate a temporary file path
const tempDir = tmpdir();
const contentBasedDirName = hash;
const configDir = path.join(tempDir, contentBasedDirName);
await mkdir(configDir)
const filePath = path.join(configDir, imgAuthConfigFilename);

// Write the JSON data to the file
await writeFile(filePath, JSON.stringify(authData));

// Return the path to the newly created temporary file
return resolve(configDir)
}

export class __ClassName extends ComponentResource {
url: string = "TODO" // will fill once i've deployed for the first time
url: Output<string>
constructor(
name: string,
args: Args,
opts?: ComponentResourceOptions
) {
super('__TYPE', name, args, opts);

const arg = all([args.repository]).apply(([repo]) => [
"--repository", `${repo}`
])

const authFile = all([args.token, args.repository]).apply(([token, registry]) => {
if (!token || !registry) return;
return createPodmanAuthFile(token, registry)
});

const upload = new local.Command(`${name}_push`, {
create:
output(args.repository).apply(repository => [
"__PUSH_BIN",
"--repository",
repository,
].join(" "))
environment: output(authFile).apply(f => ({
DOCKER_CONFIG: f,
// not supported yet by crane --
// supported from v0.20.2
// https://github.com/google/go-containerregistry/releases/tag/v0.20.2
//
// rules_oci uses v0.18.x
// https://github.com/bazel-contrib/rules_oci/blob/843eb01b152b884fe731a3fb4431b738ad00ea60/oci/private/versions.bzl#L3
//REGISTRY_AUTH_FILE: f
}) as { [v: string]: string }),
interpreter:
arg.apply(arg => [
"__PUSH_BIN",
...arg
])
}, { parent: this })

this.url = interpolate`https://${upload.stdout}`


super.registerOutputs({ upload })
}
Expand Down
2 changes: 1 addition & 1 deletion ts/pulumi/lib/oci/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def pulumi_image(
oci_push(
name = name + "_push_bin",
image = src,
repository = "why is this mandatory",
repository = "None",
)

expand_template_rule(
Expand Down
2 changes: 1 addition & 1 deletion ts/pulumi/lib/tags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { all, Input } from '@pulumi/pulumi';

type TagSet = Input<Record<string, Input<string>>>;
export type TagSet = Input<Record<string, Input<string>>>;

export const mergeTags = (a?: TagSet, b?: TagSet): TagSet =>
all([a, b]).apply(([a, b]) => ({ ...a, ...b }));
Expand Down
60 changes: 60 additions & 0 deletions ts/pulumi/zemn.me/hello_world/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
load("@rules_oci//oci:defs.bzl", "oci_image")
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
load("//bzl:rules.bzl", "bazel_lint")
load("//go:rules.bzl", "go_binary", "go_library")
load("//ts:rules.bzl", "ts_project")
load("//ts/pulumi/lib/oci:rules.bzl", "pulumi_image")

go_library(
name = "hello_world_lib",
srcs = ["hello.go"],
importpath = "github.com/zemn-me/monorepo/ts/pulumi/zemn.me/hello_world",
visibility = ["//visibility:private"],
deps = ["@com_github_aws_aws_lambda_go//lambda"],
)

go_binary(
name = "hello_world",
embed = [":hello_world_lib"],
visibility = ["//visibility:public"],
)

bazel_lint(
name = "bazel_lint",
srcs = ["BUILD.bazel"],
)

pkg_tar(
name = "tar",
srcs = [":hello_world"],
)

oci_image(
name = "image",
base = "@distroless_base",
entrypoint = ["/hello_world"],
tars = [":tar"],
)

pulumi_image(
name = "oci_image",
src = ":image",
component_name = "HelloWorldImage",
)

ts_project(
name = "ts",
srcs = [
"hello_world.ts",
],
visibility = [
"//ts/pulumi:__subpackages__",
],
deps = [
":oci_image",
"//:node_modules/@pulumi/aws",
"//:node_modules/@pulumi/awsx",
"//:node_modules/@pulumi/pulumi",
"//ts/pulumi/lib",
],
)
17 changes: 17 additions & 0 deletions ts/pulumi/zemn.me/hello_world/hello.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"context"

"github.com/aws/aws-lambda-go/lambda"
)

// Handler is the Lambda function entry point
func Handler(ctx context.Context) (string, error) {
return "Hello, World!", nil
}

func main() {
// Start the Lambda function
lambda.Start(Handler)
}
89 changes: 89 additions & 0 deletions ts/pulumi/zemn.me/hello_world/hello_world.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as aws from "@pulumi/aws";
import { ComponentResource, ComponentResourceOptions } from "@pulumi/pulumi";

import { mergeTags, TagSet, tagTrue } from "#root/ts/pulumi/lib/tags.js";
import { HelloWorldImage } from "#root/ts/pulumi/zemn.me/hello_world/HelloWorldImage.js";

export interface Args {
tags?: TagSet;
}

function clampLambdaFunctionName(name: string): string {
// Define constraints
const maxLength = 64;
const allowedCharactersRegex = /^[a-zA-Z0-9._-]+$/;

// Trim the string to the maximum allowed length
let clampedName = name.slice(0, maxLength);

// Remove invalid characters
clampedName = clampedName
.split('')
.filter(char => allowedCharactersRegex.test(char))
.join('');

// Ensure the name is at least one character long
if (clampedName.length === 0) {
throw new Error("Lambda function name must contain at least one valid character.");
}

return clampedName;
}


export class LambdaHelloWorld extends ComponentResource {
constructor(
name: string,
args: Args,
opts?: ComponentResourceOptions
) {
super("ts:pulumi:Component", name, args, opts);

const tag = name;
const tags = mergeTags(args.tags, tagTrue(tag));

// Create the ECR repository to store our container image
const repo = new aws.ecr.Repository("repo", {
forceDelete: true,
tags: tags,
});

const auth = aws.ecr.getAuthorizationToken();



// Build and push the container image
const img = new HelloWorldImage(`${name}_img`, {
repository: repo.repositoryUrl,
token: auth.then(auth => auth.authorizationToken)
});

// Create the Lambda function using the container image
const lambda = new aws.lambda.Function(`${name}_lambda`, {
name: clampLambdaFunctionName(`${name}_lambda`),
packageType: "Image",
// e.g. --
// https://658613637108.dkr.ecr.us-east-1.amazonaws.com/repo-fe6824f@sha256:c61c4b619733eb59d7c68a34d7b56e562894c9d777f26e982bc453bbcf57ab5b
imageUri: img.url,
role: new aws.iam.Role("lambdaRole", {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
Service: "lambda.amazonaws.com",
}),
}).arn,
timeout: 30,
memorySize: 512,
tags: tags,
});

// Add permissions for Lambda to log to CloudWatch
new aws.iam.RolePolicyAttachment(`${name}_lambda_logging`, {
role: lambda.role!,
policyArn: aws.iam.ManagedPolicy.AWSLambdaBasicExecutionRole,
});

// Export the Lambda function name
this.registerOutputs({
lambdaFunctionName: lambda.name,
});
}
}
5 changes: 5 additions & 0 deletions ts/pulumi/zemn.me/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { bskyDid } from '#root/project/zemn.me/bio/bio.js';
import { BlueskyDisplayNameClaim } from '#root/ts/pulumi/lib/bluesky_username_claim.js';
import { mergeTags, tagTrue } from '#root/ts/pulumi/lib/tags.js';
import Website from '#root/ts/pulumi/lib/website.js';
import { LambdaHelloWorld } from '#root/ts/pulumi/zemn.me/hello_world/hello_world.js';

export interface Args {
zoneId: Pulumi.Input<string>;
Expand Down Expand Up @@ -33,6 +34,10 @@ export class Component extends Pulumi.ComponentResource {
{ parent: this }
);

new LambdaHelloWorld(`${name}_fargate`, {
tags: args.tags
});

this.site = new Website(
`${name}_zemn_me`,
{
Expand Down
Loading