diff --git a/cloudbuild/external.pkr.hcl b/cloudbuild/external.pkr.hcl index 6508aced..c72ad03f 100644 --- a/cloudbuild/external.pkr.hcl +++ b/cloudbuild/external.pkr.hcl @@ -93,8 +93,8 @@ build { provisioner "shell" { inline = [ "echo Installing kubectl...", - "curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg", - "echo \"deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /\" | sudo tee /etc/apt/sources.list.d/kubernetes.list", + "curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg", + "echo \"deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /\" | sudo tee /etc/apt/sources.list.d/kubernetes.list", "sudo apt-get update", // kube-proxy requires conntrack to route traffic, and kubeadm v1.31+ enforces it in preflight checks "sudo apt-get install conntrack -y", @@ -132,15 +132,20 @@ build { "sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml", "echo \"Setting containerd to default to 'kne-external' repo for the sandbox image...\"", "sudo sed -i 's/registry.k8s.io/us-west1-docker.pkg.dev\\/kne-external\\/kne/g' /etc/containerd/config.toml", + "echo \"Configuring containerd registry mirrors...\"", + "sudo sed -i 's/config_path = .*/config_path = \"\\/etc\\/containerd\\/certs.d\"/' /etc/containerd/config.toml", + "sudo mkdir -p /etc/containerd/certs.d/registry.k8s.io", + "echo 'server = \"https://registry.k8s.io\"\n\n[host.\"https://us-west1-docker.pkg.dev/v2/kne-external/kne\"]\n capabilities = [\"pull\", \"resolve\"]\n override_path = true' | sudo tee /etc/containerd/certs.d/registry.k8s.io/hosts.toml", "sudo systemctl restart containerd", "cd $HOME", "git clone https://github.com/kubernetes/cloud-provider-gcp.git", - "curl -Lo bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.19.0/bazelisk-linux-amd64 && sudo install bazel /usr/local/bin/", "cd cloud-provider-gcp", "curl --create-dirs -o third_party/licenses/cloud-provider-gcp/LICENSE https://raw.githubusercontent.com/kubernetes/cloud-provider-gcp/master/LICENSE", - "bazel build cmd/auth-provider-gcp", + "export PATH=$PATH:/usr/local/go/bin", + "make auth-provider-gcp-linux-amd64", "sudo mkdir -p /etc/kubernetes/bin/", - "sudo cp bazel-bin/cmd/auth-provider-gcp/auth-provider-gcp_/auth-provider-gcp /etc/kubernetes/bin/", + # Directory is derived from same commands as in the cloud-provider-gcp Makefile + "sudo cp release/`git describe --tags --always --dirty | sed 's|.*/||'`/auth-provider-gcp/linux/amd64/auth-provider-gcp /etc/kubernetes/bin/", ] } diff --git a/cloudbuild/internal.pkr.hcl b/cloudbuild/internal.pkr.hcl index 2f255a83..b419b8ff 100644 --- a/cloudbuild/internal.pkr.hcl +++ b/cloudbuild/internal.pkr.hcl @@ -101,8 +101,8 @@ build { provisioner "shell" { inline = [ "echo Installing kubectl...", - "curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg", - "echo \"deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /\" | sudo tee /etc/apt/sources.list.d/kubernetes.list", + "curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg", + "echo \"deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /\" | sudo tee /etc/apt/sources.list.d/kubernetes.list", "sudo apt-get update", // kube-proxy requires conntrack to route traffic, and kubeadm v1.31+ enforces it in preflight checks "sudo apt-get install conntrack -y", @@ -131,14 +131,19 @@ build { "sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml", "echo \"Setting containerd to default to 'kne-external' repo for the sandbox image...\"", "sudo sed -i 's/registry.k8s.io/us-west1-docker.pkg.dev\\/kne-external\\/kne/g' /etc/containerd/config.toml", + "echo \"Configuring containerd registry mirrors...\"", + "sudo sed -i 's/config_path = .*/config_path = \"\\/etc\\/containerd\\/certs.d\"/' /etc/containerd/config.toml", + "sudo mkdir -p /etc/containerd/certs.d/registry.k8s.io", + "echo 'server = \"https://registry.k8s.io\"\n\n[host.\"https://us-west1-docker.pkg.dev/v2/kne-external/kne\"]\n capabilities = [\"pull\", \"resolve\"]\n override_path = true' | sudo tee /etc/containerd/certs.d/registry.k8s.io/hosts.toml", "sudo systemctl restart containerd", "cd $HOME", "git clone https://github.com/kubernetes/cloud-provider-gcp.git", - "curl -Lo bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.19.0/bazelisk-linux-amd64 && sudo install bazel /usr/local/bin/", "cd cloud-provider-gcp", - "bazel build cmd/auth-provider-gcp", + "export PATH=$PATH:/usr/local/go/bin", + "make auth-provider-gcp-linux-amd64", "sudo mkdir -p /etc/kubernetes/bin/", - "sudo cp bazel-bin/cmd/auth-provider-gcp/auth-provider-gcp_/auth-provider-gcp /etc/kubernetes/bin/", + # Directory is derived from same commands as in the cloud-provider-gcp Makefile + "sudo cp release/`git describe --tags --always --dirty | sed 's|.*/||'`/auth-provider-gcp/linux/amd64/auth-provider-gcp /etc/kubernetes/bin/", ] } diff --git a/go.mod b/go.mod index 7dfeac73..cd790e91 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/golang/glog v1.2.4 github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.6.0 + github.com/google/go-cmp v0.7.0 github.com/google/gopacket v1.1.19 github.com/kr/pretty v0.3.1 github.com/networkop/meshnet-cni v0.3.1-0.20230525201116-d7c306c635cf @@ -22,12 +22,12 @@ require ( github.com/openconfig/ondatra v0.5.8 github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 - github.com/scrapli/scrapligo v1.3.2 + github.com/scrapli/scrapligo v1.3.3 github.com/scrapli/scrapligocfg v1.0.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.17.0 - github.com/srl-labs/srl-controller v0.6.1 + github.com/srl-labs/srl-controller v0.7.1 github.com/srl-labs/srlinux-scrapli v0.6.0 github.com/wI2L/jsondiff v0.5.1 go.universe.tf/metallb v0.14.8 @@ -35,7 +35,7 @@ require ( golang.org/x/sync v0.18.0 google.golang.org/api v0.169.0 google.golang.org/grpc v1.65.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.36.7 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.31.2 k8s.io/apimachinery v0.31.2 @@ -55,7 +55,7 @@ require ( github.com/Microsoft/go-winio v0.6.0 // indirect github.com/carlmontanari/difflibgo v0.0.0-20210718194309-31b9e131c298 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/creack/pty v1.1.21 // indirect + github.com/creack/pty v1.1.23 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -65,7 +65,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect diff --git a/go.sum b/go.sum index 42721fa3..9462483b 100644 --- a/go.sum +++ b/go.sum @@ -867,8 +867,8 @@ github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= -github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -933,8 +933,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -1017,8 +1017,9 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -1181,8 +1182,8 @@ github.com/networkop/meshnet-cni v0.3.1-0.20230525201116-d7c306c635cf/go.mod h1: github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= +github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= github.com/open-traffic-generator/keng-operator v0.3.34 h1:aD7FHe4j27gTv+o5kIdfLT6zZkTerDDSyHU5Mc2tGeQ= github.com/open-traffic-generator/keng-operator v0.3.34/go.mod h1:4lDEwPyrSuvaE1dOxU9po+dOZWyk9xYRXI/6yneWgAQ= github.com/open-traffic-generator/snappi/gosnappi v0.13.7 h1:qrisl9OcqHdhUXVIJ0BXUAO8MDWf2qraNn+Oic+b8JM= @@ -1273,8 +1274,8 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/scrapli/scrapligo v1.0.0/go.mod h1:jvRMdb90MNnswMiku8UNXj8JZaOIPhwhcqqFwr9qeoY= github.com/scrapli/scrapligo v1.1.7/go.mod h1:rRx/rT2oNPYztiT3/ik0FRR/Ro7AdzN/eR9AtF8A81Y= -github.com/scrapli/scrapligo v1.3.2 h1:9D5TFM/DlqAijqH18uNHygbNos0ReDsJl/vhMRObkhg= -github.com/scrapli/scrapligo v1.3.2/go.mod h1:VnmqW27qUU1NOt6PNllZNJqAXQddn2vqZpk7g5qxebw= +github.com/scrapli/scrapligo v1.3.3 h1:D9zj1QrOYNYAQ30YT7wfQBINvPGxvs5L5Lz+2LnL7V4= +github.com/scrapli/scrapligo v1.3.3/go.mod h1:pOWxVyPsQRrWTrkoSSDg05tjOqtWfLffAZtAsCc0w3M= github.com/scrapli/scrapligocfg v1.0.0 h1:540SuGqqM6rKN87SLCfR54IageQ6s3a/ZOycGRgbbak= github.com/scrapli/scrapligocfg v1.0.0/go.mod h1:9+6k9dQeIqEZEg6EK5YXEjuVb7h+nvvel26CY1RGjy4= github.com/sirikothe/gotextfsm v1.0.1-0.20200816110946-6aa2cfd355e4 h1:FHUL2HofYJuslFOQdy/JjjP36zxqIpd/dcoiwLMIs7k= @@ -1297,8 +1298,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= -github.com/srl-labs/srl-controller v0.6.1 h1:hHduqG41wglpeVPD85RALTwWWcS+NqvU8V1pHJMQIZo= -github.com/srl-labs/srl-controller v0.6.1/go.mod h1:PedxdPZPtDcC+wDOKhG6uXR4xgkHxb4JhW1cXNk/eaY= +github.com/srl-labs/srl-controller v0.7.1 h1:QZST5zXfXGCdSQUEb22iMvAwfQhfOcqzA3+Ae+ifd70= +github.com/srl-labs/srl-controller v0.7.1/go.mod h1:0QQEBd/vIn2PrXf5vgJ3jUsePjWgr19EkVN/VEGGsAE= github.com/srl-labs/srlinux-scrapli v0.6.0 h1:YQjckD+a7f6u2M+k4SmJUrDa7BFvoOTb2mMbPe6hLZM= github.com/srl-labs/srlinux-scrapli v0.6.0/go.mod h1:8hCoel3XaSyZD8hxSs8Pij/uZqaccd57mfeHgc0oJhM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1380,6 +1381,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.universe.tf/metallb v0.14.8 h1:MBW6lLJqRgu32s7httfceh1vw8h9qp26ZkI4WaT35zI= go.universe.tf/metallb v0.14.8/go.mod h1:F08YRmgnuiMyvZ8/21dYnh11CFFmYimnm9vafWyvyGs= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -2114,8 +2117,8 @@ google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/manifests/controllers/srlinux/manifest.yaml b/manifests/controllers/srlinux/manifest.yaml index 1861fd15..ba211a4b 100644 --- a/manifests/controllers/srlinux/manifest.yaml +++ b/manifests/controllers/srlinux/manifest.yaml @@ -15,8 +15,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.10.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.16.5 name: srlinuxes.kne.srlinux.dev spec: group: kne.srlinux.dev @@ -49,14 +48,19 @@ spec: description: Srlinux is the Schema for the srlinuxes API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string license_key: description: license key from license secret that contains a license file @@ -71,6 +75,7 @@ spec: description: NodeConfig represents srlinux node configuration parameters. properties: args: + description: Command args to pass into the pod. items: type: string type: array @@ -93,6 +98,7 @@ spec: type: integer type: object command: + description: Command to pass into pod. items: type: string type: array @@ -117,8 +123,14 @@ spec: description: Map of environment variables to pass into the pod. type: object image: + description: Container image to use with for the SR Linux container. + type: string + init-image: + description: Init container image to use with for the SR Linux + container. type: string sleep: + description: Sleep time before starting the pod. format: int32 type: integer type: object @@ -132,9 +144,9 @@ spec: num-interfaces: type: integer version: - description: Version may be set in kne topology as a mean to explicitly - provide version information in case it is not encoded in the image - tag + description: |- + Version may be set in kne topology as a mean to explicitly provide version information + in case it is not encoded in the image tag type: string type: object status: @@ -144,9 +156,9 @@ spec: description: Image used to run srlinux pod type: string ready: - description: Ready is true if the srlinux NOS is ready to receive - config. This is when management server is running and initial commit - is processed. + description: |- + Ready is true if the srlinux NOS is ready to receive config. + This is when management server is running and initial commit is processed. type: boolean startup-config: description: StartupConfig contains the status of the startup-config. @@ -157,8 +169,9 @@ spec: type: string type: object status: - description: 'Status is the status of the srlinux custom resource. - Can be one of: "created", "running", "error".' + description: |- + Status is the status of the srlinux custom resource. + Can be one of: "created", "running", "error". type: string type: object type: object @@ -228,36 +241,13 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: srlinux-controller-manager-role rules: - apiGroups: - "" resources: - configmaps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - secrets verbs: - create @@ -490,7 +480,7 @@ spec: - --leader-elect command: - /manager - image: ghcr.io/srl-labs/srl-controller:v0.6.1 + image: ghcr.io/srl-labs/srl-controller:v0.7.1 livenessProbe: httpGet: path: /healthz diff --git a/manifests/kube/credential-provider-config.yaml b/manifests/kube/credential-provider-config.yaml index a13b4aa6..bd5cdd31 100644 --- a/manifests/kube/credential-provider-config.yaml +++ b/manifests/kube/credential-provider-config.yaml @@ -8,6 +8,7 @@ providers: - "gcr.io" - "*.gcr.io" - "*.pkg.dev" + - "registry.k8s.io" args: - get-credentials - --v=3 diff --git a/proto/topo.proto b/proto/topo.proto index 4af374c7..454b06a8 100644 --- a/proto/topo.proto +++ b/proto/topo.proto @@ -44,6 +44,7 @@ enum Vendor { ALPINE = 11; DRIVENETS = 12; FORWARD = 13; + IN_CLUSTER_PROXY = 14; } // Node is a single container inside the topology @@ -65,6 +66,7 @@ message Node { CISCO_XRD = 12; CISCO_E8000 = 13; LEMMING = 14; + IN_CLUSTER_PROXY = 15; } string name = 1; // Name of the node in the topology. Must be unique. Type type = 2 [deprecated = true]; diff --git a/topo/node/inclusterproxy/README.md b/topo/node/inclusterproxy/README.md new file mode 100644 index 00000000..4e030f12 --- /dev/null +++ b/topo/node/inclusterproxy/README.md @@ -0,0 +1,80 @@ +# IN_CLUSTER_PROXY Node Type + +The `IN_CLUSTER_PROXY` node type is a specialized KNE node designed to act as a back-to-back proxy inside the cluster. It binds to a specific target node (e.g., a Device Under Test / DUT) over a single dedicated link and forwards configured ports to it using `socat`. + +## Features + +- **Automatic Command Generation**: Automatically computes static IP address sizing for sidecar point-to-point subnets and generates `socat` listener scriptlets directly without writing bash boilerplate. +- **Cross-Stack Support**: Transparently supports both point-to-point **IPv4 (`/31`)** and **IPv6 (`/127`)** addressing setups. +- **Static Topology Integrity Verification**: Proactively verifies that `eth1` connects directly to the declared target node backplane before attempting to load or deploy. + +## Node Constraints + +To pass static validation, the node **must** meet the following conditions: + +| Parameter | Constraint | +| :--- | :--- | +| **Interfaces** | Exactly one interface named `eth1`. | +| **Links** | `eth1` **must** link directly to the node specified in the `proxy-pool-for` label. | +| **Services** | Exactly one Service mapping must be provided inside `Services` map. | +| **Labels** | The node must have the `proxy-pool-for` label correctly populated. | + +## Configuration Labels + +| Label Key | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| `proxy-pool-for` | String | **Yes** | Name of the target node this proxy is mediating. | +| `peer-ip` | IP | No (Opt-in) | IP address of the peer (DUT) connected over `eth1` (e.g. `192.168.100.1` or `2001:db8::1`). | +| `peer-prefix` | String | No (Opt-in) | Prefix length of the peer IP (e.g. `31` or `127`). | +| `target-port` | Integer | No (Opt-in) | Port on the peer node to forward proxy streams to. | + +> **Note on Opt-in Automatic Setup**: +> If **all three of** `peer-ip`, `peer-prefix`, and `target-port` are provided, the controller will automatically calculate the inverse IP (your side of the `/31` or `/127` link) and generate full commands addressing `socat`. If omitted, users must configure `command` and `args` in `.Config` structures manually. + +--- + +## Example (Protobuf text format) + +Below is an example of an `IN_CLUSTER_PROXY` node mediating a BGP lookup connection to node `cx1`. + +```protobuf +nodes: { + name: "bgp-proxy-1" + vendor: IN_CLUSTER_PROXY + labels: { + key: "proxy-pool-for" + value: "cx1" + } + labels: { + key: "peer-ip" + value: "192.168.100.1" + } + labels: { + key: "peer-prefix" + value: "31" + } + labels: { + key: "target-port" + value: "179" + } + services: { + key: 1790 + value: { + name: "bgp-proxy" + inside: 1790 + } + } +} + +links: { + a_node: "bgp-proxy-1" + a_int: "eth1" + z_node: "cx1" + z_int: "eth1" +} +``` + +In this example, the proxy container will automatically spin up to: + +1. Assign `192.168.100.0/31` to its `eth1` interface. +2. Run `socat` forwarding any stream sent to port `1790` out to `192.168.100.1:179` across the wire. diff --git a/topo/node/inclusterproxy/inclusterproxy.go b/topo/node/inclusterproxy/inclusterproxy.go new file mode 100644 index 00000000..04c250ea --- /dev/null +++ b/topo/node/inclusterproxy/inclusterproxy.go @@ -0,0 +1,176 @@ +// Package inclusterproxy implements a node type that acts as an in-cluster proxy. +package inclusterproxy + +import ( + "context" + "fmt" + "net" + "strings" + + tpb "github.com/openconfig/kne/proto/topo" + "github.com/openconfig/kne/topo/node" + log "k8s.io/klog/v2" +) + +var ( + defaultNode = tpb.Node{ + Name: "default_incluster_proxy", + Config: &tpb.Config{ + Image: "nicolaka/netshoot:latest", + }, + } +) + +func New(nodeImpl *node.Impl) (node.Node, error) { + if nodeImpl == nil { + return nil, fmt.Errorf("nodeImpl cannot be nil") + } + if nodeImpl.Proto == nil { + return nil, fmt.Errorf("nodeImpl.Proto cannot be nil") + } + defaults(nodeImpl.Proto) + n := &Node{ + Impl: nodeImpl, + } + if err := n.validate(); err != nil { + return nil, err + } + return n, nil +} + +type Node struct { + *node.Impl +} + +// deriveAdjacentIP calculates the static IP for the proxy side of a point-to-point link. +// It assumes a /31 mask for IPv4 or /127 mask for IPv6, where there are only two addresses +// in the subnet. Flipping the last bit of the peer IP gives the adjacent IP for the other side of the link. +func deriveAdjacentIP(cidr string) (string, string, bool, error) { + ip, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + return "", "", false, err + } + ones, _ := ipNet.Mask.Size() + + ip4 := ip.To4() + if ip4 != nil { + if ones != 31 { + return "", "", false, fmt.Errorf("only /31 mask is supported for IPv4 static IP calculation") + } + staticIP := make(net.IP, 4) + copy(staticIP, ip4) + staticIP[3] ^= 1 + return fmt.Sprintf("%s/31", staticIP.String()), ip.String(), false, nil + } + + if ones != 127 { + return "", "", false, fmt.Errorf("only /127 mask is supported for IPv6 static IP calculation") + } + staticIP := make(net.IP, 16) + copy(staticIP, ip) + staticIP[15] ^= 1 + return fmt.Sprintf("%s/127", staticIP.String()), ip.String(), true, nil +} + +func defaults(pb *tpb.Node) { + if pb.Config == nil { + pb.Config = &tpb.Config{} + } + if pb.Config.Image == "" { + pb.Config.Image = defaultNode.Config.Image + } + if pb.Labels == nil { + return + } + peerIPLabel := pb.Labels["peer-ip"] + peerPrefixLabel := pb.Labels["peer-prefix"] + targetPort := pb.Labels["target-port"] + if peerIPLabel != "" && peerPrefixLabel != "" && targetPort != "" && len(pb.Services) == 1 { + staticIPWithMask, peerIPStr, isV6, err := deriveAdjacentIP(fmt.Sprintf("%s/%s", peerIPLabel, peerPrefixLabel)) + if err == nil { + var insidePort uint32 + for k := range pb.Services { + insidePort = pb.Services[k].Inside + break + } + socatListen := "TCP-LISTEN" + socatConnect := "TCP" + if isV6 { + socatListen = "TCP6-LISTEN" + socatConnect = "TCP6" + } + pb.Config.Command = []string{"/bin/sh", "-c"} + pb.Config.Args = []string{ + fmt.Sprintf("ip addr add %s dev eth1 && ip link set eth1 up && sleep 2 && /usr/bin/socat -d -d %s:%d,reuseaddr,fork %s:%s:%s", staticIPWithMask, socatListen, insidePort, socatConnect, peerIPStr, targetPort), + } + } + } +} + +func (n *Node) validate() error { + pb := n.GetProto() + + // Enforce proxy-pool-for label + if pb.Labels == nil || pb.Labels["proxy-pool-for"] == "" { + return fmt.Errorf("node %s: label 'proxy-pool-for' is required", n.Name()) + } + + // Enforce exactly one interface: eth1 + if len(pb.Interfaces) != 1 { + return fmt.Errorf("node %s: exactly one interface is required, found %d", n.Name(), len(pb.Interfaces)) + } + _, ok := pb.Interfaces["eth1"] + if !ok { + return fmt.Errorf("node %s: interface must be 'eth1'", n.Name()) + } + + // Ensure exactly 1 service + if len(pb.Services) != 1 { + return fmt.Errorf("node %s: exactly one service must be configured, found %d", n.Name(), len(pb.Services)) + } + + peerIPLabel := pb.Labels["peer-ip"] + peerPrefixLabel := pb.Labels["peer-prefix"] + targetPort := pb.Labels["target-port"] + if peerIPLabel != "" || peerPrefixLabel != "" || targetPort != "" { + if peerIPLabel == "" || peerPrefixLabel == "" || targetPort == "" { + return fmt.Errorf("node %s: 'peer-ip', 'peer-prefix', and 'target-port' labels must be provided together for automatic socat generation", n.Name()) + } + if _, _, _, err := deriveAdjacentIP(fmt.Sprintf("%s/%s", peerIPLabel, peerPrefixLabel)); err != nil { + return fmt.Errorf("node %s: invalid 'peer-ip' or 'peer-prefix' label: %v", n.Name(), err) + } + } else { + // Warning if socat is not in command/args and generation is skipped + hasSocat := false + for _, c := range pb.Config.Command { + if strings.Contains(c, "socat") { + hasSocat = true + break + } + } + if !hasSocat { + for _, a := range pb.Config.Args { + if strings.Contains(a, "socat") { + hasSocat = true + break + } + } + } + if !hasSocat { + log.Warningf("node %s: command/args do not contain 'socat', which may be needed for proxying", n.Name()) + } + } + + return nil +} + +func (n *Node) Create(ctx context.Context) error { + if err := n.validate(); err != nil { + return err + } + return n.Impl.Create(ctx) +} + +func init() { + node.Vendor(tpb.Vendor(14), New) +} diff --git a/topo/node/inclusterproxy/inclusterproxy_test.go b/topo/node/inclusterproxy/inclusterproxy_test.go new file mode 100644 index 00000000..1325cb9e --- /dev/null +++ b/topo/node/inclusterproxy/inclusterproxy_test.go @@ -0,0 +1,272 @@ +package inclusterproxy + +import ( + "testing" + + "github.com/openconfig/gnmi/errdiff" + topopb "github.com/openconfig/kne/proto/topo" + "github.com/openconfig/kne/topo/node" + "google.golang.org/protobuf/proto" +) + +func TestNew(t *testing.T) { + tests := []struct { + desc string + ni *node.Impl + wantPB *topopb.Node + wantErr string + }{{ + desc: "nil node impl", + wantErr: "nodeImpl cannot be nil", + }, { + desc: "nil pb", + wantErr: "nodeImpl.Proto cannot be nil", + ni: &node.Impl{}, + }, { + desc: "missing proxy-pool-for label", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + }, + }, + wantErr: "label 'proxy-pool-for' is required", + }, { + desc: "missing interfaces", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "exactly one interface is required", + }, { + desc: "too many interfaces", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {}, + "eth2": {}, + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "exactly one interface is required", + }, { + desc: "wrong interface name", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Interfaces: map[string]*topopb.Interface{ + "eth2": {}, + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "interface must be 'eth1'", + }, { + desc: "multiple services not allowed", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{ + 1: {Inside: 1}, + 2: {Inside: 2}, + }, + }, + }, + wantErr: "exactly one service must be configured", + }, { + desc: "valid pb manual command", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{1790: {Inside: 1790}}, + Config: &topopb.Config{ + Command: []string{"socat"}, + }, + }, + }, + wantPB: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + }, + Config: &topopb.Config{ + Image: "nicolaka/netshoot:latest", + Command: []string{"socat"}, + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{1790: {Inside: 1790}}, + }, + }, { + desc: "valid pb with automatic generation ipv4", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "192.168.100.1", + "peer-prefix": "31", + "target-port": "179", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{ + 1790: {Inside: 1790}, + }, + }, + }, + wantPB: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "192.168.100.1", + "peer-prefix": "31", + "target-port": "179", + }, + Config: &topopb.Config{ + Image: "nicolaka/netshoot:latest", + Command: []string{"/bin/sh", "-c"}, + Args: []string{"ip addr add 192.168.100.0/31 dev eth1 && ip link set eth1 up && sleep 2 && /usr/bin/socat -d -d TCP-LISTEN:1790,reuseaddr,fork TCP:192.168.100.1:179"}, + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{ + 1790: {Inside: 1790}, + }, + }, + }, { + desc: "valid pb with automatic generation ipv6", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "2001:db8::1", + "peer-prefix": "127", + "target-port": "179", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{ + 1790: {Inside: 1790}, + }, + }, + }, + wantPB: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "2001:db8::1", + "peer-prefix": "127", + "target-port": "179", + }, + Config: &topopb.Config{ + Image: "nicolaka/netshoot:latest", + Command: []string{"/bin/sh", "-c"}, + Args: []string{"ip addr add 2001:db8::/127 dev eth1 && ip link set eth1 up && sleep 2 && /usr/bin/socat -d -d TCP6-LISTEN:1790,reuseaddr,fork TCP6:2001:db8::1:179"}, + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{ + 1790: {Inside: 1790}, + }, + }, + }, { + desc: "invalid peer-ip format", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "invalid-ip", + "peer-prefix": "31", + "target-port": "179", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "invalid 'peer-ip' or 'peer-prefix' label", + }, { + desc: "invalid peer-ip mask v4", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "192.168.100.1", + "peer-prefix": "24", + "target-port": "179", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "only /31 mask is supported for IPv4", + }, { + desc: "invalid peer-ip mask v6", + ni: &node.Impl{ + Proto: &topopb.Node{ + Name: "test_node", + Labels: map[string]string{ + "proxy-pool-for": "dut1", + "peer-ip": "2001:db8::1", + "peer-prefix": "64", + "target-port": "179", + }, + Interfaces: map[string]*topopb.Interface{ + "eth1": {PeerName: "dut1"}, + }, + Services: map[uint32]*topopb.Service{1: {Inside: 1}}, + }, + }, + wantErr: "only /127 mask is supported for IPv6", + }} + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + impl, err := New(tt.ni) + if s := errdiff.Substring(err, tt.wantErr); s != "" { + t.Fatalf("unexpected error: got: %v, want: %s", err, s) + } + if tt.wantErr != "" { + return + } + if !proto.Equal(impl.GetProto(), tt.wantPB) { + t.Fatalf("New() failed: got\n%v\nwant\n%v", impl.GetProto(), tt.wantPB) + } + }) + } +} diff --git a/topo/node/nokia/nokia.go b/topo/node/nokia/nokia.go index 2a2dfe74..6769f3c2 100644 --- a/topo/node/nokia/nokia.go +++ b/topo/node/nokia/nokia.go @@ -266,6 +266,7 @@ func (n *Node) Create(ctx context.Context) error { Command: n.GetProto().GetConfig().GetCommand(), Args: n.GetProto().GetConfig().GetArgs(), Image: n.GetProto().GetConfig().GetImage(), + InitImage: n.GetProto().GetConfig().GetInitImage(), Env: n.GetProto().GetConfig().GetEnv(), EntryCommand: n.GetProto().GetConfig().GetEntryCommand(), ConfigPath: n.GetProto().GetConfig().GetConfigPath(), diff --git a/topo/topo.go b/topo/topo.go index 85d5e2c7..2794c7e3 100644 --- a/topo/topo.go +++ b/topo/topo.go @@ -58,6 +58,7 @@ import ( _ "github.com/openconfig/kne/topo/node/forward" _ "github.com/openconfig/kne/topo/node/gobgp" _ "github.com/openconfig/kne/topo/node/host" + _ "github.com/openconfig/kne/topo/node/inclusterproxy" _ "github.com/openconfig/kne/topo/node/juniper" _ "github.com/openconfig/kne/topo/node/keysight" _ "github.com/openconfig/kne/topo/node/nokia"