Skip to content

Commit

Permalink
Write cilium-agent-proxy in Go
Browse files Browse the repository at this point in the history
Signed-off-by: Daichi Sakaue <[email protected]>
  • Loading branch information
yokaze committed Oct 22, 2024
1 parent ffdfbb0 commit 7ede7ee
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 68 deletions.
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Build the manager binary
FROM ghcr.io/cybozu/golang:1.23-jammy AS builder

# 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 cmd/cilium-agent-proxy/ cmd/cilium-agent-proxy/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o cilium-agent-proxy ./cmd/cilium-agent-proxy

# Compose the manager container
FROM ghcr.io/cybozu/ubuntu:22.04
LABEL org.opencontainers.image.source=https://github.com/cybozu-go/network-policy-viewer

WORKDIR /
COPY --from=builder /work/cilium-agent-proxy /

USER 10000:10000
ENTRYPOINT ["/cilium-agent-proxy"]
7 changes: 7 additions & 0 deletions cmd/cilium-agent-proxy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/cybozu-go/network-policy-viewer/cmd/cilium-agent-proxy/sub"

func main() {
sub.Execute()
}
53 changes: 53 additions & 0 deletions cmd/cilium-agent-proxy/sub/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package sub

import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os/exec"
"path/filepath"
"strconv"
)

const (
ciliumPath = "/cilium"
)

func runCommand(path string, input []byte, args ...string) ([]byte, []byte, error) {
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd := exec.Command(path, args...)
cmd.Stdout = stdout
cmd.Stderr = stderr
if input != nil {
cmd.Stdin = bytes.NewReader(input)
}
if err := cmd.Run(); err != nil {
_, file := filepath.Split(path)
return stdout.Bytes(), stderr.Bytes(), fmt.Errorf("%s failed with %s: stderr=%s", file, err, stderr)
}
return stdout.Bytes(), stderr.Bytes(), nil
}

func renderJSON(w http.ResponseWriter, path string, data []byte, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if _, err := w.Write(data); err != nil {
slog.Error("failed to write response", slog.String("path", path))
}
}

func renderError(w http.ResponseWriter, path string, message string, status int) {
slog.Info(message, slog.String("path", path), slog.Int("status", status))
ret := make(map[string]string)
ret["error"] = message
ret["status"] = strconv.Itoa(status)

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if err := json.NewEncoder(w).Encode(ret); err != nil {
slog.Error("failed to write response", slog.String("path", path))
}
}
26 changes: 26 additions & 0 deletions cmd/cilium-agent-proxy/sub/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package sub

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "cilium-agent-proxy",
Short: "cilium-agent proxy",
Long: `cilium-agent proxy`,

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
return subMain()
},
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
94 changes: 94 additions & 0 deletions cmd/cilium-agent-proxy/sub/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package sub

import (
"bytes"
"context"
"fmt"
"io"
"net"
"net/http"
"strconv"
)

const socketPath = "/var/run/cilium/cilium.sock"

var (
socketClient *http.Client
)

func handleEndpoint(w http.ResponseWriter, r *http.Request) {
param := r.URL.Path[len("/v1/endpoint/"):]
if len(param) == 0 {
renderError(w, r.URL.Path, "failed to read endpoint ID", http.StatusBadRequest)
return
}

// Convert to number to avoid parameter injection
endpoint, err := strconv.Atoi(param)
if err != nil {
renderError(w, r.URL.Path, "failed to read endpoint ID", http.StatusBadRequest)
return
}

url := fmt.Sprintf("http://localhost/v1/endpoint/%d", endpoint)
resp, err := socketClient.Get(url)
if err != nil {
renderError(w, r.URL.Path, "failed to call Cilium API", http.StatusInternalServerError)
return
}

buf := new(bytes.Buffer)
io.Copy(buf, resp.Body)
renderJSON(w, r.URL.Path, buf.Bytes(), http.StatusOK)
}

func handleIdentity(w http.ResponseWriter, r *http.Request) {
param := r.URL.Path[len("/v1/identity/"):]
if len(param) == 0 {
renderError(w, r.URL.Path, "failed to read identity", http.StatusBadRequest)
return
}

// Convert to number to avoid parameter injection
identity, err := strconv.Atoi(param)
if err != nil {
renderError(w, r.URL.Path, "failed to read identity", http.StatusBadRequest)
return
}

url := fmt.Sprintf("http://localhost/v1/identity/%d", identity)
resp, err := socketClient.Get(url)
if err != nil {
renderError(w, r.URL.Path, "failed to call Cilium API", http.StatusInternalServerError)
return
}

buf := new(bytes.Buffer)
io.Copy(buf, resp.Body)
renderJSON(w, r.URL.Path, buf.Bytes(), http.StatusOK)
}

func handlePolicy(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "error\n")
}

func subMain() error {
socketClient = &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", socketPath)
},
},
}

server := http.Server{
Addr: ":8080",
Handler: nil,
}

http.HandleFunc("/v1/endpoint/", handleEndpoint)
http.HandleFunc("/v1/identity/", handleIdentity)
http.HandleFunc("/policy/", handlePolicy)

return server.ListenAndServe()
}
6 changes: 3 additions & 3 deletions cmd/npv/sub/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ func parseDerivedFromEntry(input []string, direction string) derivedFromEntry {
func runList(ctx context.Context, w io.Writer, name string) error {
_, dynamicClient, client, err := createClients(ctx, name)
if err != nil {
return err
return fmt.Errorf("failed to create clients: %w", err)
}

endpointID, err := getPodEndpointID(ctx, dynamicClient, rootOptions.namespace, name)
if err != nil {
return err
return fmt.Errorf("failed to get pod endpoint ID: %w", err)
}

params := endpoint.GetEndpointIDParams{
Expand All @@ -90,7 +90,7 @@ func runList(ctx context.Context, w io.Writer, name string) error {
}
response, err := client.Endpoint.GetEndpointID(&params)
if err != nil {
return err
return fmt.Errorf("failed to get endpoint information: %w", err)
}

// The same rule appears multiple times in the response, so we need to dedup it
Expand Down
4 changes: 4 additions & 0 deletions e2e/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ start:
--namespace kube-system \
--set image.pullPolicy=IfNotPresent \
--set ipam.mode=kubernetes

cd ..; docker build . -t cilium-agent-proxy:dev
kind load docker-image cilium-agent-proxy:dev

kustomize build testdata | kubectl apply -f -
$(MAKE) --no-print-directory wait-for-workloads

Expand Down
11 changes: 2 additions & 9 deletions e2e/testdata/cilium-agent-proxy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@ spec:
securityContext:
fsGroup: 0
containers:
- image: ghcr.io/cybozu/envoy
name: envoy
command: ["envoy", "-c", "/etc/envoy/envoy-config.yaml"]
args: []
- image: ghcr.io/cybozu-go/cilium-agent-proxy
name: proxy
volumeMounts:
- name: cilium-socket
mountPath: /var/run/cilium
- name: envoy-config
mountPath: /etc/envoy
securityContext:
capabilities:
drop:
Expand All @@ -32,6 +28,3 @@ spec:
- name: cilium-socket
hostPath:
path: /var/run/cilium
- name: envoy-config
configMap:
name: cilium-agent-proxy
49 changes: 0 additions & 49 deletions e2e/testdata/envoy-config.yaml

This file was deleted.

10 changes: 3 additions & 7 deletions e2e/testdata/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ kind: Kustomization
resources:
- cilium-agent-proxy.yaml
- ubuntu.yaml
configMapGenerator:
- namespace: kube-system
name: cilium-agent-proxy
files:
- envoy-config.yaml
images:
- name: ghcr.io/cybozu/envoy
newTag: 1.28.1.1
- name: ghcr.io/cybozu-go/cilium-agent-proxy
newName: cilium-agent-proxy
newTag: dev

0 comments on commit 7ede7ee

Please sign in to comment.