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

[pkov2] agent RPC server #624

Merged
merged 22 commits into from
Aug 8, 2024
Merged
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
54 changes: 54 additions & 0 deletions .github/workflows/v2-run-acceptance-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: Pulumi Kubernetes Operator PR Builds
on:
pull_request:
branches:
- v2
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:

build:
runs-on: ubuntu-latest
name: Build
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser-pro
# 'latest', 'nightly', or a semver
version: '~> v2'
args: release --snapshot --clean --skip=docker

agent-integration-tests:
runs-on: ubuntu-latest
name: Integration Testing
if: github.event_name == 'repository_dispatch' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Install Pulumi
uses: pulumi/actions@v5
- name: Run Tests
run: make -C agent test
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
file: agent/coverage.out
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
45 changes: 44 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
version: 2
project_name: pulumi-kubernetes-operator

builds:
Expand All @@ -18,6 +19,25 @@ builds:
main: ./cmd/manager/main.go
binary: pulumi-kubernetes-operator

- id: pulumi-kubernetes-agent
ldflags:
- -X github.com/pulumi/pulumi-kubernetes-operator/agent/version.Version={{.Version}}
- -w -extldflags "-static"
flags:
- -a
- -tags
- netgo
goos:
- linux
goarch:
- amd64
env:
- CGO_ENABLED=0
- GO111MODULE=on
main: ./main.go
dir: agent
binary: pulumi-kubernetes-agent

archives:
- name_template: >-
{{ .ProjectName }}_
Expand All @@ -44,7 +64,7 @@ release:
name_template: "{{.ProjectName}}-v{{.Version}}"

dockers:
-
- id: pulumi-kubernetes-operator
# GOOS of the built binary that should be used.
goos: linux

Expand All @@ -65,3 +85,26 @@ dockers:
- "--label=org.label-schema.name={{ .ProjectName }}"
- "--label=org.label-schema.vcs-ref={{ .ShortCommit }}"
- "--label=org.label-schema.vcs-url='{{ .GitURL }}'"

- id: pulumi-kubernetes-agent
# GOOS of the built binary that should be used.
goos: linux

# GOARCH of the built binary that should be used.
goarch: amd64

# Path to the Dockerfile (from the project root).
dockerfile: agent/Dockerfile

# Templates of the Docker image names.
image_templates:
- "pulumi/pulumi-kubernetes-agent:latest"
- "pulumi/pulumi-kubernetes-agent:{{ .Version }}"

build_flag_templates:
- "--pull"
- "--label=org.label-schema.build-date={{.Date}}"
- "--label=org.label-schema.name={{ .ProjectName }}"
- "--label=org.label-schema.vcs-ref={{ .ShortCommit }}"
- "--label=org.label-schema.vcs-url='{{ .GitURL }}'"

23 changes: 23 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,29 @@
"args": [
"--zap-level=debug"
]
},
{
"name": "Agent",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "agent",
"args": [
"serve",
"-v=false",
"--workspace=${input:workdir}",
"-s=dev"
],
"env": {
"AWS_REGION": "us-west-1",
}
}
],
"inputs": [
{
"id": "workdir",
"description": "Please provide the Pulumi program directory",
"type": "promptString"
}
]
}
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,7 @@ version:
dep-tidy:
go mod tidy

.PHONY: build build-static codegen generate-crds install-crds generate-k8s test version dep-tidy build-image push-image push-image-latest deploy prep-spec
agent:
cd agent && $(MAKE) agent

.PHONY: build build-static codegen generate-crds install-crds generate-k8s test version dep-tidy build-image push-image push-image-latest deploy prep-spec agent
2 changes: 2 additions & 0 deletions agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pulumi-kubernetes-agent
coverage.out
34 changes: 34 additions & 0 deletions agent/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Build the agent binary
FROM golang:1.22 AS builder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FROM golang:1.22 AS builder
FROM --platform=$BUILDPLATFORM golang:1.22 AS builder

This will build in a native image instead of an emulated one when cross-compiling.

ARG TARGETOS
ARG TARGETARCH
ARG VERSION

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum

# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY cmd/ cmd/
COPY pkg/ pkg/
COPY version/ version/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -ldflags "-X github.com/pulumi/pulumi-kubernetes-operator/agent/version.Version=${VERSION}" -a -o agent main.go

# runtime image
FROM gcr.io/distroless/static-debian12:debug-nonroot

# install agent binary
WORKDIR /
COPY --from=builder /workspace/agent agent
26 changes: 26 additions & 0 deletions agent/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
VERSION ?= $(shell git describe --tags --always --dirty)

all: protoc agent

ensure:
go mod tidy

protoc:
@echo "Generating Go files"
cd pkg/proto && protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative *.proto

test:
go test -covermode=atomic -coverprofile=coverage.out -v ./...

agent: protoc
@echo "Building agent"
go build -o pulumi-kubernetes-agent \
-ldflags "-X github.com/pulumi/pulumi-kubernetes-operator/agent/version.Version=${VERSION}" \
github.com/pulumi/pulumi-kubernetes-operator/agent

image: agent
docker build --build-arg="VERSION=$(VERSION)" -t pulumi/pulumi-kubernetes-agent:latest .

.PHONY: agent protoc image ensure test

83 changes: 83 additions & 0 deletions agent/cmd/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
Copyright © 2024 Pulumi Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd

import (
"os"

"github.com/fluxcd/pkg/http/fetch"
"github.com/spf13/cobra"
"go.uber.org/zap"
)

const (
DefaultFluxRetries = 3
)

var (
TargetDir string
FluxUrl string
FluxDigest string
)

// initCmd represents the init command
var initCmd = &cobra.Command{
Use: "init",
Short: "Initialize a Pulumi workspace",
Long: `Initialize a working directory to contain project sources.

For Flux sources:
pulumi-kubernetes-agent init --flux-fetch-url URL
`,
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
log.Debugw("executing init command", "TargetDir", TargetDir)

err := os.MkdirAll(TargetDir, 0777)
if err != nil {
log.Errorw("fatal: unable to make target directory", zap.Error(err))
os.Exit(1)
}
log.Debugw("target directory created", "dir", TargetDir)

// fetch the configured flux source
if FluxUrl != "" {
// https://github.com/fluxcd/kustomize-controller/blob/a1a33f2adda783dd2a17234f5d8e84caca4e24e2/internal/controller/kustomization_controller.go#L328
fetcher := fetch.New(
fetch.WithRetries(DefaultFluxRetries),
fetch.WithHostnameOverwrite(os.Getenv("SOURCE_CONTROLLER_LOCALHOST")),
fetch.WithUntar())

log.Infow("flux source fetching", "url", FluxUrl, "digest", FluxDigest)
err := fetcher.FetchWithContext(ctx, FluxUrl, FluxDigest, TargetDir)
if err != nil {
log.Errorw("fatal: unable to fetch flux source", zap.Error(err))
os.Exit(2)
}
log.Infow("flux source fetched", "dir", TargetDir)
}
},
}

func init() {
rootCmd.AddCommand(initCmd)
initCmd.Flags().StringVarP(&TargetDir, "target-dir", "t", "", "The target directory to initialize")
initCmd.MarkFlagRequired("target-dir")

initCmd.Flags().StringVar(&FluxUrl, "flux-url", "", "Flux archive URL")
initCmd.Flags().StringVar(&FluxDigest, "flux-digest", "", "Flux digest")
initCmd.MarkFlagsRequiredTogether("flux-url", "flux-digest")
}
72 changes: 72 additions & 0 deletions agent/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright © 2024 Pulumi Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd

import (
"os"

"github.com/spf13/cobra"
"go.uber.org/zap"
)

var verbose bool

// a command-specific logger
var log *zap.SugaredLogger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structured logging ❤️


// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "agent",
Short: "Pulumi Kubernetes Operator Agent",
Long: `Provides tooling and a gRPC service for the Pulumi Kubernetes Operator
to use to perform stack operations.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var err error

// initialize the global logger
zc := zap.NewDevelopmentConfig()
zc.DisableCaller = true
if !verbose {
zc.Level.SetLevel(zap.InfoLevel)
}
zapLog, err := zc.Build()
if err != nil {
return err
}
zap.ReplaceGlobals(zapLog)

// initialize a command-specific logger
log = zap.L().Named("cmd").Named(cmd.Name()).Sugar()
return nil
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
// ignore sync errors: https://github.com/uber-go/zap/pull/347
_ = zap.L().Sync()
},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

func init() {
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging")
}
Loading