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

Implement list command #2

Merged
merged 5 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
22 changes: 15 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- main
env:
cache-version: 1
cache-version: "2024-04-05"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you use date as cache-version?
And also, I wonder if we need cache-version. Are there any cases that hashFiles is not sufficient?

Copy link
Contributor Author

@yokaze yokaze Apr 8, 2024

Choose a reason for hiding this comment

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

@chez-shanpu
It is an old practice to allow invalidating caches when it is contaminated by a broken CI workflow.
However I always hesitate to update the version one: it looks like having a special meaning. Using a date looks more meaningless.

Copy link
Contributor

Choose a reason for hiding this comment

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

@yokaze I see. How about deleting a cache like gh cache delete when it is contaminated instead of using cache-version?

Copy link
Contributor Author

@yokaze yokaze Apr 9, 2024

Choose a reason for hiding this comment

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

@chez-shanpu
It looks reasonable, I removed the cache-version parameter. Thanks for the info!

jobs:
test:
name: e2e
Expand All @@ -16,19 +16,27 @@ jobs:
with:
go-version-file: go.mod
- name: Cache tools
id: cache-tools
uses: actions/cache@v3
with:
path: bin/download
key: cache-${{ env.cache-version }}-go-${{ hashFiles('go.mod') }}-${{ hashFiles('Makefile') }}
key: cache-tools-${{ env.cache-version }}-go-${{ hashFiles('go.mod') }}-${{ hashFiles('Makefile') }}
- name: Cache files
uses: actions/cache@v3
with:
path: cache
key: cache-files-${{ env.cache-version }}-go-${{ hashFiles('go.mod') }}-${{ hashFiles('Makefile') }}
- name: Setup tools
if: steps.cache-tools.outputs.cache-hit != 'true'
run: make setup
- name: Run code check
run: make check-generate
- name: Run lint
run: make lint
- name: Run environment
run: make start
working-directory: e2e
- name: Install
run: make install
run: |
make start
make install-test-pod
make install-policy-viewer
- name: Test
working-directory: e2e
run: make test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@

# Generated files
/bin
/cache
/docs/book
42 changes: 30 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
BIN_DIR := $(shell pwd)/bin
TOOLS_DIR := $(BIN_DIR)/download
CACHE_DIR := $(shell pwd)/cache

HELM_VERSION := 3.14.3
JQ_VERSION := 1.7.1
KIND_VERSION := 0.22.0
Expand All @@ -9,8 +11,10 @@ YQ_VERSION := 4.43.1

# Test tools
CUSTOMCHECKER := $(TOOLS_DIR)/custom-checker
HELM := $(TOOLS_DIR)/helm
HELM_BINARY := $(TOOLS_DIR)/helm
HELM := $(HELM_BINARY) --repository-cache $(CACHE_DIR)/helm/repository --repository-config $(CACHE_DIR)/helm/repositories.yaml
JQ := $(TOOLS_DIR)/jq
KIND := $(TOOLS_DIR)/kind
KUBECTL := $(TOOLS_DIR)/kubectl
KUSTOMIZE := $(TOOLS_DIR)/kustomize
STATICCHECK := $(TOOLS_DIR)/staticcheck
Expand All @@ -26,39 +30,48 @@ help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

.PHONY: setup
setup: $(HELM) $(JQ) $(KUBECTL) $(KUSTOMIZE) $(YQ) ## Install necessary tools
GOBIN=$(TOOLS_DIR) go install sigs.k8s.io/kind@v$(KIND_VERSION)
GOBIN=$(TOOLS_DIR) go install honnef.co/go/tools/cmd/staticcheck@latest
GOBIN=$(TOOLS_DIR) go install github.com/cybozu-go/golang-custom-analyzer/cmd/custom-checker@latest
setup: $(CUSTOMCHECKER) $(HELM_BINARY) $(KIND) $(JQ) $(KUBECTL) $(KUSTOMIZE) $(STATICCHECK) $(YQ) ## Install necessary tools
$(HELM) repo add cilium https://helm.cilium.io/
$(HELM) repo update cilium

$(TOOLS_DIR):
mkdir -p $(TOOLS_DIR)
chez-shanpu marked this conversation as resolved.
Show resolved Hide resolved
$(CUSTOMCHECKER):
GOBIN=$(TOOLS_DIR) go install github.com/cybozu-go/golang-custom-analyzer/cmd/custom-checker@latest

$(HELM): $(TOOLS_DIR)
$(HELM_BINARY):
mkdir -p $(TOOLS_DIR)
wget -qO - https://get.helm.sh/helm-v$(HELM_VERSION)-linux-amd64.tar.gz | tar zx -O linux-amd64/helm > $@
chmod +x $@

$(JQ): $(TOOLS_DIR)
$(JQ):
mkdir -p $(TOOLS_DIR)
wget -qO $@ https://github.com/jqlang/jq/releases/download/jq-$(JQ_VERSION)/jq-linux-amd64
chmod +x $@

$(KUBECTL): $(TOOLS_DIR)
$(KIND):
GOBIN=$(TOOLS_DIR) go install sigs.k8s.io/kind@v$(KIND_VERSION)

$(KUBECTL):
mkdir -p $(TOOLS_DIR)
wget -qO $@ https://storage.googleapis.com/kubernetes-release/release/v$(KUBECTL_VERSION)/bin/linux/amd64/kubectl
chmod +x $@

$(KUSTOMIZE): $(TOOLS_DIR)
$(KUSTOMIZE):
mkdir -p $(TOOLS_DIR)
wget -qO - https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv$(KUSTOMIZE_VERSION)/kustomize_v$(KUSTOMIZE_VERSION)_linux_amd64.tar.gz | tar zx -O kustomize > $@
chmod +x $@

$(YQ): $(TOOLS_DIR)
$(STATICCHECK):
GOBIN=$(TOOLS_DIR) go install honnef.co/go/tools/cmd/staticcheck@latest

$(YQ):
mkdir -p $(TOOLS_DIR)
wget -qO $@ https://github.com/mikefarah/yq/releases/download/v$(YQ_VERSION)/yq_linux_amd64
chmod +x $@

.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -rf $(CACHE_DIR)

##@ Development

Expand All @@ -67,6 +80,11 @@ build: ## Build cilium-policy-viewer
mkdir -p $(BIN_DIR)
go build -o $(BIN_DIR)/cilium-policy main.go

.PHONY: check-generate
check-generate:
go mod tidy
git diff --exit-code --name-only

.PHONY: lint
lint: ## Run lint tools
go vet ./...
Expand Down
59 changes: 10 additions & 49 deletions cmd/dump.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
package cmd

import (
"bytes"
"context"
"errors"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

var dumpOptions struct {
namespace string
}

func init() {
dumpCmd.Flags().StringVarP(&dumpOptions.namespace, "namespace", "n", "", "namespace of a pod")
rootCmd.AddCommand(dumpCmd)
}

Expand All @@ -37,54 +27,22 @@ var dumpCmd = &cobra.Command{
}

func runDump(ctx context.Context, name string) error {
config, err := rest.InClusterConfig()
clientset, dynamicClient, _, err := createClients(ctx, name)
if err != nil {
return err
}

clientset, _ := kubernetes.NewForConfig(config)
pod, err := clientset.CoreV1().Pods(dumpOptions.namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return err
}
node := pod.Spec.NodeName
proxy, err := clientset.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{
FieldSelector: "spec.nodeName=" + node,
LabelSelector: "app.kubernetes.io/name=cilium-agent-proxy",
})
endpointID, err := getPodEndpointID(ctx, dynamicClient, rootOptions.namespace, name)
if err != nil {
return err
}
if len(proxy.Items) != 1 {
return errors.New("proxy not found")
}
proxyIP := proxy.Items[0].Status.PodIP

client, err := dynamic.NewForConfig(config)
proxyEndpoint, err := getProxyEndpoint(ctx, clientset, rootOptions.namespace, name)
if err != nil {
return err
}

gvr := schema.GroupVersionResource{
Group: "cilium.io",
Version: "v2",
Resource: "ciliumendpoints",
}
obj, err := client.Resource(gvr).Namespace(dumpOptions.namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return err
}

endpointID, found, err := unstructured.NestedInt64(obj.Object, "status", "id")
if err != nil {
return err
}
if !found {
return errors.New("endpoint not found")
}

url := fmt.Sprintf("http://%s:8080/v1/endpoint/%d", proxyIP, endpointID)
resp, err := http.Get(url)
resp, err := http.Get(proxyEndpoint + fmt.Sprintf("/v1/endpoint/%d", endpointID))
if err != nil {
return err
}
Expand All @@ -93,6 +51,9 @@ func runDump(ctx context.Context, name string) error {
if err != nil {
return err
}
fmt.Println(string(data))

var buf bytes.Buffer
json.Indent(&buf, data, "", " ")
fmt.Println(buf.String())
return nil
}
91 changes: 91 additions & 0 deletions cmd/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/cilium/cilium/pkg/client"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

func createClients(ctx context.Context, name string) (*kubernetes.Clientset, *dynamic.DynamicClient, *client.Client, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, nil, nil, err
}

// Create Kubernetes Clients
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, nil, nil, err
}

dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
return nil, nil, nil, err
}

// Create Cilium Client
endpoint, err := getProxyEndpoint(ctx, clientset, rootOptions.namespace, name)
if err != nil {
return nil, nil, nil, err
}
ciliumClient, err := client.NewClient(endpoint)
if err != nil {
return nil, nil, nil, err
}

return clientset, dynamicClient, ciliumClient, err
}

func getProxyEndpoint(ctx context.Context, c *kubernetes.Clientset, namespace, name string) (string, error) {
targetPod, err := c.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return "", err
}
targetNode := targetPod.Spec.NodeName

pods, err := c.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{
FieldSelector: "spec.nodeName=" + targetNode,
LabelSelector: rootOptions.proxySelector,
})
if err != nil {
return "", err
}
if num := len(pods.Items); num != 1 {
err := fmt.Errorf("failed to find cilium-agent-proxy. found %d pods", num)
return "", err
}

podIP := pods.Items[0].Status.PodIP
return fmt.Sprintf("http://%s:%d", podIP, rootOptions.proxyPort), nil
}

func getPodEndpointID(ctx context.Context, d *dynamic.DynamicClient, namespace, name string) (int64, error) {
gvr := schema.GroupVersionResource{
Group: "cilium.io",
Version: "v2",
Resource: "ciliumendpoints",
}

ep, err := d.Resource(gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return 0, err
}

endpointID, found, err := unstructured.NestedInt64(ep.Object, "status", "id")
if err != nil {
return 0, err
}
if !found {
return 0, errors.New("endpoint resource is broken")
}

return endpointID, nil
}
Loading
Loading