From 39edbd279392f001268004eb96c100de4bff8dd3 Mon Sep 17 00:00:00 2001 From: Mangirdas Judeikis Date: Wed, 12 Nov 2025 11:00:58 +0200 Subject: [PATCH] Clean documentation, examples. Start consolidating towards "cowboys" Add CLI styling to show output cleaner Signed-off-by: Mangirdas Judeikis On-behalf-of: @SAP mangirdas.judeikis@sap.com --- README.md | 3 +- backend/oidc/oidc.go | 2 - cli/go.mod | 21 +- cli/go.sum | 45 +- cli/pkg/kubectl/dev/plugin/create.go | 117 +++-- contrib/kcp/README.md | 100 +---- .../examples/apiresourceschema-cowboys.yaml | 11 + .../examples/apiresourceschema-sheriffs.yaml | 14 + .../examples/apiserviceexport-namespaced.yaml | 27 -- .../deploy/examples/collection-wildwest.yaml | 9 - contrib/kcp/deploy/examples/cowboy.yaml | 7 - contrib/kcp/deploy/examples/examples.go | 41 ++ contrib/kcp/deploy/examples/sheriff.yaml | 6 - .../deploy/examples/template-sheriffs.yaml | 35 -- contrib/kcp/go.mod | 2 +- contrib/kcp/go.sum | 4 +- contrib/kcp/test/e2e/kcp_test.go | 18 +- deploy/examples/apiresourceschema.yaml | 41 -- deploy/examples/collection.yaml | 4 +- deploy/examples/cr-cowboy.yaml | 23 + deploy/examples/cr-sheriff.yaml | 26 ++ deploy/examples/crd-cowboys.yaml | 60 +++ deploy/examples/crd-foo.yaml | 47 -- deploy/examples/crd-mangodb.yaml | 40 -- deploy/examples/crd-sheriffs.yaml | 61 +++ deploy/examples/examples.go | 41 ++ deploy/examples/foo.yaml | 7 - deploy/examples/mangodb.yaml | 9 - deploy/examples/servicenamespace-example.yaml | 5 - .../examples/template-cowboys.yaml | 16 +- deploy/examples/template-foo.yaml | 33 -- deploy/examples/template-mangodb.yaml | 23 - .../examples/template-sheriffs.yaml | 16 +- docs/content/developers/dev-environments.md | 408 +++--------------- docs/content/setup/kcp-setup.md | 136 ++---- docs/generators/cli-doc/go.mod | 6 +- docs/generators/cli-doc/go.sum | 12 +- go.mod | 4 +- go.sum | 4 +- 39 files changed, 605 insertions(+), 879 deletions(-) delete mode 100644 contrib/kcp/deploy/examples/apiserviceexport-namespaced.yaml delete mode 100644 contrib/kcp/deploy/examples/collection-wildwest.yaml delete mode 100644 contrib/kcp/deploy/examples/cowboy.yaml create mode 100644 contrib/kcp/deploy/examples/examples.go delete mode 100644 contrib/kcp/deploy/examples/sheriff.yaml delete mode 100644 contrib/kcp/deploy/examples/template-sheriffs.yaml delete mode 100644 deploy/examples/apiresourceschema.yaml create mode 100644 deploy/examples/cr-cowboy.yaml create mode 100644 deploy/examples/cr-sheriff.yaml create mode 100644 deploy/examples/crd-cowboys.yaml delete mode 100644 deploy/examples/crd-foo.yaml delete mode 100644 deploy/examples/crd-mangodb.yaml create mode 100644 deploy/examples/crd-sheriffs.yaml create mode 100644 deploy/examples/examples.go delete mode 100644 deploy/examples/foo.yaml delete mode 100644 deploy/examples/mangodb.yaml delete mode 100644 deploy/examples/servicenamespace-example.yaml rename {contrib/kcp/deploy => deploy}/examples/template-cowboys.yaml (50%) delete mode 100644 deploy/examples/template-foo.yaml delete mode 100644 deploy/examples/template-mangodb.yaml rename contrib/kcp/deploy/examples/apiserviceexport-cluster.yaml => deploy/examples/template-sheriffs.yaml (56%) diff --git a/README.md b/README.md index 46c0612cc..7075a7fa3 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ This is the 3 line pitch: ```shell $ kubectl krew index add bind https://github.com/kube-bind/krew-index.git $ kubectl krew install bind/bind -$ kubectl bind https://mangodb/exports +$ kubectl bind login https://mangodb +$ kubectl bind Redirect to the brower to authenticate via OIDC. BOOM โ€“ the MangoDB API is available in the local cluster, without anything MangoDB-specific running. diff --git a/backend/oidc/oidc.go b/backend/oidc/oidc.go index 79a84df14..8d20680fd 100644 --- a/backend/oidc/oidc.go +++ b/backend/oidc/oidc.go @@ -25,7 +25,6 @@ import ( "slices" "time" - "github.com/davecgh/go-spew/spew" "github.com/gorilla/mux" "github.com/xrstf/mockoidc" ) @@ -101,7 +100,6 @@ func (s *Server) Config(callbackURL, issuerURL string) (*Config, error) { CallbackURL: callbackURL, IssuerURL: issuerURL, } - spew.Dump(c) return c, nil } diff --git a/cli/go.mod b/cli/go.mod index 16f55a463..725de7e30 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -10,6 +10,9 @@ replace ( require ( github.com/MakeNowJust/heredoc v1.0.0 github.com/blang/semver/v4 v4.0.0 + github.com/charmbracelet/bubbles v0.21.0 + github.com/charmbracelet/bubbletea v1.3.10 + github.com/charmbracelet/lipgloss v1.1.0 github.com/docker/docker v28.5.2+incompatible github.com/fatih/color v1.18.0 github.com/kube-bind/kube-bind v0.0.0-00010101000000-000000000000 @@ -41,9 +44,14 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/x/ansi v0.10.1 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect github.com/containerd/containerd v1.7.28 // indirect github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect @@ -55,6 +63,7 @@ require ( github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/evanphx/json-patch v5.9.11+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect @@ -88,10 +97,12 @@ require ( github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.12 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -103,6 +114,9 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/onsi/gomega v1.36.2 // indirect @@ -116,7 +130,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rubenv/sql-migrate v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect @@ -125,6 +139,7 @@ require ( github.com/spf13/cast v1.7.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect @@ -136,7 +151,7 @@ require ( golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect diff --git a/cli/go.sum b/cli/go.sum index 463cb4828..0210ccb22 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -28,6 +28,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -40,6 +42,20 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= +github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= +github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= +github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/containerd/containerd v1.7.28 h1:Nsgm1AtcmEh4AHAJ4gGlNSaKgXiNccU270Dnf81FQ3c= github.com/containerd/containerd v1.7.28/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= @@ -83,6 +99,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= @@ -188,6 +206,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -195,8 +215,11 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= @@ -227,8 +250,14 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= @@ -269,8 +298,9 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnA github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o= @@ -304,6 +334,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= @@ -367,6 +399,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= @@ -388,11 +422,12 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -411,7 +446,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= diff --git a/cli/pkg/kubectl/dev/plugin/create.go b/cli/pkg/kubectl/dev/plugin/create.go index ae1278596..0f91c63d3 100644 --- a/cli/pkg/kubectl/dev/plugin/create.go +++ b/cli/pkg/kubectl/dev/plugin/create.go @@ -90,8 +90,8 @@ func (o *DevOptions) AddCmdFlags(cmd *cobra.Command) { cmd.Flags().DurationVarP(&o.WaitForReadyTimeout, "wait-for-ready-timeout", "", 2*time.Minute, "Timeout for waiting for the cluster to be ready") cmd.Flags().StringVarP(&o.ChartPath, "chart-path", "", o.ChartPath, "Helm chart path or OCI registry URL") cmd.Flags().StringVarP(&o.ChartVersion, "chart-version", "", o.ChartVersion, "Helm chart version") - cmd.Flags().StringVarP(&o.Image, "image", "", "ghcr.io/kube-bind/backend", "Kube-bind backend image to use in dev mode") - cmd.Flags().StringVarP(&o.Tag, "tag", "", "main", "Kube-bind backend image tag to use in dev mode") + cmd.Flags().StringVarP(&o.Image, "image", "", "ghcr.io/kube-bind/backend", "kube-bind backend image to use in dev mode") + cmd.Flags().StringVarP(&o.Tag, "tag", "", "main", "kube-bind backend image tag to use in dev mode") } // Complete completes the options @@ -124,16 +124,30 @@ nodes: - role: control-plane ` -// Run executes the create command -func (o *DevOptions) Run(ctx context.Context) error { +// Color helper functions +func blueCommand(text string) string { + return "\033[38;5;67m" + text + "\033[0m" +} + +func redText(text string) string { + return "\033[31m" + text + "\033[0m" +} + +func (o *DevOptions) runWithColors(ctx context.Context) error { _ = o.Options.GetConfig() - // Display experimental warning header - fmt.Fprintf(o.Streams.ErrOut, "๐Ÿงช EXPERIMENTAL: Kube-bind dev command is in preview\n") - fmt.Fprintf(o.Streams.ErrOut, "๐Ÿ“ฆ Requirements: Docker must be installed and running\n") + // Display experimental warning header with red "EXPERIMENTAL" + fmt.Fprintf(o.Streams.ErrOut, "kube-bind Development Environment Setup\n\n") + fmt.Fprintf(o.Streams.ErrOut, "%s kube-bind dev command is in preview\n", redText("EXPERIMENTAL:")) + fmt.Fprintf(o.Streams.ErrOut, "Requirements: Docker must be installed and running\n\n") + hostEntryExisted := false if err := o.setupHostEntries(ctx); err != nil { - return err + fmt.Fprintf(o.Streams.ErrOut, "โš ๏ธ Host entry setup warning: %v\n", err) + hostEntryExisted = false + } else { + fmt.Fprint(o.Streams.ErrOut, "โœ“ Host entry exists for kube-bind.dev.local\n") + hostEntryExisted = true } if err := o.checkFileLimits(); err != nil { @@ -147,35 +161,58 @@ func (o *DevOptions) Run(ctx context.Context) error { providerIP, err := o.getClusterIPAddress(ctx, o.ProviderClusterName, "kube-bind-dev") if err != nil { fmt.Fprintf(o.Streams.ErrOut, "โš ๏ธ Failed to get provider cluster IP address: %v\n", err) - fmt.Fprintf(o.Streams.ErrOut, "๐Ÿ’ก Fallback: Use docker command to get IP manually:\n") - fmt.Fprintf(o.Streams.ErrOut, " docker inspect %s-control-plane | jq -r '.[0].NetworkSettings.Networks[\"kube-bind-dev\"].IPAddress'\n", o.ProviderClusterName) - } else { - fmt.Fprintf(o.Streams.ErrOut, "Provider cluster IP address: %s\n", providerIP) + providerIP = "" } if err := o.createCluster(ctx, o.ConsumerClusterName, consumerClusterConfig, false); err != nil { return err } - message := "๐Ÿš€ Kube-bind dev environment is ready!\n\n" + - "- Provider cluster kubeconfig: " + o.ProviderClusterName + ".kubeconfig\n" + - "- Consumer cluster kubeconfig: " + o.ConsumerClusterName + ".kubeconfig\n" + - "- Kube-bind server URL: http://kube-bind.dev.local:8080\n" + - "- Next steps:\n" + - " 1. Run login to authenticate to the provider cluster:\n\n" + - "kubectl bind login http://kube-bind.dev.local:8080\n\n" + - " 2. Run bind to bind an API service from the provider to the consumer cluster:\n\n" - if providerIP == "" { - message += fmt.Sprintf("PROVIDER_IP=$(docker inspect %s-control-plane | jq -r '.[0].NetworkSettings.Networks[\"kube-bind-dev\"].IPAddress')\n", o.ProviderClusterName) - message += "KUBECONFIG=" + o.ConsumerClusterName + ".kubeconfig kubectl bind --konnector-host-alias ${PROVIDER_IP}:kube-bind.dev.local\n" + // Success message + fmt.Fprint(o.Streams.ErrOut, "kube-bind dev environment is ready!\n\n") + + // Configuration + fmt.Fprint(o.Streams.ErrOut, "Configuration:\n") + fmt.Fprintf(o.Streams.ErrOut, "โ€ข Provider cluster kubeconfig: %s.kubeconfig\n", o.ProviderClusterName) + fmt.Fprintf(o.Streams.ErrOut, "โ€ข Consumer cluster kubeconfig: %s.kubeconfig\n", o.ConsumerClusterName) + fmt.Fprint(o.Streams.ErrOut, "โ€ข kube-bind server URL: http://kube-bind.dev.local:8080\n\n") + + // Next steps with colored commands + fmt.Fprint(o.Streams.ErrOut, "Next Steps:\n\n") + + stepNum := 1 + + // Only show /etc/hosts step if entry didn't already exist + if !hostEntryExisted { + fmt.Fprintf(o.Streams.ErrOut, "%d. Add to /etc/hosts (if not already done):\n", stepNum) + fmt.Fprintf(o.Streams.ErrOut, "%s\n\n", blueCommand("echo '127.0.0.1 kube-bind.dev.local' | sudo tee -a /etc/hosts")) + stepNum++ + } + + fmt.Fprintf(o.Streams.ErrOut, "%d. Login to authenticate to the provider cluster:\n", stepNum) + fmt.Fprintf(o.Streams.ErrOut, "%s\n\n", blueCommand("kubectl bind login http://kube-bind.dev.local:8080")) + stepNum++ + + fmt.Fprintf(o.Streams.ErrOut, "%d. Bind an API service from provider to consumer:\n", stepNum) + if providerIP != "" { + fmt.Fprintf(o.Streams.ErrOut, "%s\n", blueCommand(fmt.Sprintf("KUBECONFIG=%s.kubeconfig kubectl bind --konnector-host-alias %s:kube-bind.dev.local", o.ConsumerClusterName, providerIP))) } else { - message += "KUBECONFIG=" + o.ConsumerClusterName + ".kubeconfig kubectl bind --konnector-host-alias " + providerIP + ":kube-bind.dev.local\n" + fmt.Fprintf(o.Streams.ErrOut, "%s\n", blueCommand(fmt.Sprintf("PROVIDER_IP=$(docker inspect %s-control-plane | jq -r '.[0].NetworkSettings.Networks[\"kube-bind-dev\"].IPAddress') && KUBECONFIG=%s.kubeconfig kubectl bind --konnector-host-alias ${PROVIDER_IP}:kube-bind.dev.local", o.ProviderClusterName, o.ConsumerClusterName))) } - fmt.Fprint(o.Streams.ErrOut, message) return nil } +// Run runs the dev command +func (o *DevOptions) Run(ctx context.Context) error { + return o.runWithColors(ctx) +} + +// SetupHostEntries sets up the host entries for the dev environment +func (o *DevOptions) SetupHostEntries(ctx context.Context) error { + return o.setupHostEntries(ctx) +} + func (o *DevOptions) setupHostEntries(ctx context.Context) error { if err := addHostEntry("kube-bind.dev.local"); err != nil { fmt.Fprintf(o.Streams.ErrOut, "Warning: Could not automatically add host entry. Please run:\n") @@ -490,6 +527,36 @@ func hostEntryExists(hostsPath, hostname string) (bool, error) { return false, scanner.Err() } +// CheckFileLimits checks system file limits for the dev environment +func (o *DevOptions) CheckFileLimits() error { + return o.checkFileLimits() +} + +// GetClusterIPAddress gets the IP address of a cluster in the specified network +func (o *DevOptions) GetClusterIPAddress(ctx context.Context, clusterName, networkName string) (string, error) { + return o.getClusterIPAddress(ctx, clusterName, networkName) +} + +// CreateProviderCluster creates the provider cluster +func (o *DevOptions) CreateProviderCluster(ctx context.Context) error { + return o.createCluster(ctx, o.ProviderClusterName, providerClusterConfig, true) +} + +// CreateConsumerCluster creates the consumer cluster +func (o *DevOptions) CreateConsumerCluster(ctx context.Context) error { + return o.createCluster(ctx, o.ConsumerClusterName, consumerClusterConfig, false) +} + +// GetProviderClusterName returns the provider cluster name +func (o *DevOptions) GetProviderClusterName() string { + return o.ProviderClusterName +} + +// GetConsumerClusterName returns the consumer cluster name +func (o *DevOptions) GetConsumerClusterName() string { + return o.ConsumerClusterName +} + func (o *DevOptions) checkFileLimits() error { // Only check on Linux systems if runtime.GOOS != "linux" { diff --git a/contrib/kcp/README.md b/contrib/kcp/README.md index a91254924..05fc942da 100644 --- a/contrib/kcp/README.md +++ b/contrib/kcp/README.md @@ -25,13 +25,7 @@ It will do the following: ## Preparation -1. Start dex - -```bash -make run-dex -``` - -2. Start kcp +1. Start kcp ```bash make run-kcp @@ -45,21 +39,18 @@ cp .kcp/admin.kubeconfig .kcp/backend.kubeconfig export KUBECONFIG=.kcp/backend.kubeconfig ./bin/kcp-init --kcp-kubeconfig $KUBECONFIG ``` -4. Run the backend: +3. Run the backend: ``` k ws use :root:kube-bind ./bin/backend \ --multicluster-runtime-provider kcp \ --server-url=$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath="{.status.endpoints[0].url}") \ - --oidc-issuer-client-secret=ZXhhbXBsZS1hcHAtc2VjcmV0 \ - --oidc-issuer-client-id=kube-bind \ - --oidc-issuer-url=http://127.0.0.1:5556/dex \ - --oidc-callback-url=http://127.0.0.1:8080/api/callback \ --pretty-name="BigCorp.com" \ + --oidc-type=embedded \ + --oidc-issuer-url=http://127.0.0.1:8080/oidc \ + --oidc-callback-url=http://127.0.0.1:8080/api/callback \ --namespace-prefix="kube-bind-" \ - --cookie-signing-key=bGMHz7SR9XcI9JdDB68VmjQErrjbrAR9JdVqjAOKHzE= \ - --cookie-encryption-key=wadqi4u+w0bqnSrVFtM38Pz2ykYVIeeadhzT34XlC1Y= \ --schema-source apiresourceschemas \ --consumer-scope=cluster ``` @@ -68,7 +59,7 @@ This process will keep running, so open a new terminal. ## Provider -5. Copy the kubeconfig to the provider and create provider workspace: +4. Copy the kubeconfig to the provider and create provider workspace: ```bash cp .kcp/admin.kubeconfig .kcp/provider.kubeconfig export KUBECONFIG=.kcp/provider.kubeconfig @@ -76,7 +67,7 @@ k ws use :root kubectl create-workspace provider --enter ``` -6. Bind the APIExport to the provider workspace +5. Bind the APIExport to the provider workspace ```bash kubectl kcp bind apiexport root:kube-bind:kube-bind.io \ --accept-permission-claim clusterrolebindings.rbac.authorization.k8s.io \ @@ -91,29 +82,29 @@ kubectl kcp bind apiexport root:kube-bind:kube-bind.io \ --accept-permission-claim apiresourceschemas.apis.kcp.io ``` -7. Create CRD in provider: +6. Create CRD in provider: ```bash kubectl apply -f contrib/kcp/deploy/examples/apiexport.yaml kubectl apply -f contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml kubectl apply -f contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml kubectl kcp bind apiexport root:provider:cowboys-stable -kubectl apply -f contrib/kcp/deploy/examples/template-cowboys.yaml -kubectl apply -f contrib/kcp/deploy/examples/template-sheriffs.yaml -kubectl apply -f contrib/kcp/deploy/examples/collection-wildwest.yaml +kubectl apply -f deploy/examples/template-cowboys.yaml +kubectl apply -f deploy/examples/template-sheriffs.yaml +kubectl apply -f deploy/examples/collection.yaml ``` -8. Get LogicalCluster: +7. Get LogicalCluster: ```bash kubectl get logicalcluster # NAME PHASE URL AGE -# cluster Ready https://192.168.2.166:6443/clusters/1y7tqtsucxaekmqu +# cluster Ready https://192.168.2.166:6443/clusters/2ocmmccjkme8bof4 ``` ## Consumer -9. Now we gonna initiate consumer: +8. Now we gonna initiate consumer: ```bash cp .kcp/admin.kubeconfig .kcp/consumer.kubeconfig export KUBECONFIG=.kcp/consumer.kubeconfig @@ -121,10 +112,10 @@ kubectl ws use :root kubectl ws create consumer --enter ``` -10. Bind the thing: +9. Bind the thing: ```bash -./bin/kubectl-bind login http://127.0.0.1:8080 --cluster 7yw1thtocnvdhf74 +./bin/kubectl-bind login http://127.0.0.1:8080 --cluster 2ocmmccjkme8bof4 ./bin/kubectl-bind --dry-run -o yaml > apiserviceexport.yaml # Extract secret for binding process. Note that secret name is not the same as output from command above. Check secret @@ -146,60 +137,9 @@ Start konnector: ./bin/konnector --lease-namespace default --kubeconfig .kcp/consumer.kubeconfig ``` -Optionally add second consumer to test - -```bash -cp .kcp/admin.kubeconfig .kcp/consumer2.kubeconfig -export KUBECONFIG=.kcp/consumer2.kubeconfig -kubectl ws use :root -kubectl ws create consumer2 --enter - -./bin/kubectl-bind http://127.0.0.1:8080/clusters/2vgrh380y0cq38du/exports --dry-run -o yaml > apiserviceexport2.yaml - -kubectl get secrets -n kube-bind -o jsonpath='{.items[0].data.kubeconfig}' | base64 -d > remote2.kubeconfig - -./bin/kubectl-bind apiservice -v 6 --remote-kubeconfig remote2.kubeconfig -f apiserviceexport2.yaml --skip-konnector --remote-namespace "$(yq '.contexts[0].context.namespace' remote2.kubeconfig)" - -./bin/konnector --lease-namespace default --kubeconfig .kcp/consumer2.kubeconfig --server-address :8091 -``` - -This will keep running, so switch to a new terminal. - -## Testing - -Create objects: -``` -export KUBECONFIG=.kcp/consumer.kubeconfig -kubectl apply -f contrib/kcp/deploy/examples/cowboy.yaml -kubectl apply -f contrib/kcp/deploy/examples/sheriff.yaml -``` - -## Debug +# Create an instance ```bash - -cp .kcp/admin.kubeconfig .kcp/debug.kubeconfig -export KUBECONFIG=.kcp/debug.kubeconfig -k ws use :root:kube-bind - -k -s "$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath='{.status.endpoints[0].url}')/clusters/*" api-resources - -k -s "$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath='{.status.endpoints[0].url}')/clusters/*" get crd - -namespace=$(yq '.contexts[0].context.namespace' remote.kubeconfig) - -# some claimed objects - -kubectl create cm provider -n "$namespace-default" -kubectl label cm provider app=wildwest -n "$namespace-default" - -kubectl create cm consumer -n default -kubectl label cm consumer app=wildwest -n default - -kubectl create secret generic provider-secret -kubectl label secret provider-secret app=wildwest - -kubectl create namespace bob -kubectl create secret generic wildwest-secrets1 -n bob -kubectl label secret wildwest-secrets1 app=wildwest -n bob -``` +kubectl apply -f deploy/examples/cr-cowboy.yaml +kubectl apply -f deploy/examples/cr-sheriff.yaml +``` \ No newline at end of file diff --git a/contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml b/contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml index 8eeccbd44..72f922f5a 100644 --- a/contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml +++ b/contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml @@ -34,6 +34,17 @@ spec: properties: intent: type: string + weapons: + type: array + description: "Array of references to Secrets containing weapon permits and licenses" + items: + type: object + properties: + name: + type: string + description: "Name of the referenced Secret" + required: + - name type: object status: description: CowboyStatus communicates the observed state of the Cowboy. diff --git a/contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml b/contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml index dfbdb00ba..f97057133 100644 --- a/contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml +++ b/contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml @@ -34,6 +34,20 @@ spec: properties: intent: type: string + secretRefs: + type: array + description: "Array of references to multiple Secrets for sheriff operations" + items: + type: object + properties: + name: + type: string + description: "Name of the referenced Secret" + namespace: + type: string + description: "Namespace of the referenced Secret" + required: + - name type: object status: description: SheriffStatus communicates the observed state of the Sheriff. diff --git a/contrib/kcp/deploy/examples/apiserviceexport-namespaced.yaml b/contrib/kcp/deploy/examples/apiserviceexport-namespaced.yaml deleted file mode 100644 index 53c43920d..000000000 --- a/contrib/kcp/deploy/examples/apiserviceexport-namespaced.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: APIServiceExportRequest -metadata: - name: cowboys.wildwest.dev -spec: - resources: - - group: wildwest.dev - resource: cowboys - versions: - - v1alpha1 - permissionClaims: - - apiGroup: "" - resource: configmaps - selector: - labelSelector: - matchLabels: - app: wildwest - - apiGroup: "" - resource: secrets - selector: - labelSelector: - matchLabels: - app: wildwest - namedResource: - - name: wildwest-secrets - namespace: bob -status: {} diff --git a/contrib/kcp/deploy/examples/collection-wildwest.yaml b/contrib/kcp/deploy/examples/collection-wildwest.yaml deleted file mode 100644 index 90e123a8d..000000000 --- a/contrib/kcp/deploy/examples/collection-wildwest.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: Collection -metadata: - name: wildwest -spec: - description: "A collection of Wild West service definitions including Cowboys and Sheriffs for frontier management" - templates: - - name: cowboys - - name: sheriffs \ No newline at end of file diff --git a/contrib/kcp/deploy/examples/cowboy.yaml b/contrib/kcp/deploy/examples/cowboy.yaml deleted file mode 100644 index 369dc9695..000000000 --- a/contrib/kcp/deploy/examples/cowboy.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: wildwest.dev/v1alpha1 -kind: Cowboy -metadata: - name: my-cowboy - namespace: default -spec: - intent: "ride into the sunset" diff --git a/contrib/kcp/deploy/examples/examples.go b/contrib/kcp/deploy/examples/examples.go new file mode 100644 index 000000000..2b84f329c --- /dev/null +++ b/contrib/kcp/deploy/examples/examples.go @@ -0,0 +1,41 @@ +/* +Copyright 2025 The Kube Bind Authors. + +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 examples + +import ( + "context" + "embed" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/discovery" + "k8s.io/client-go/dynamic" + + "github.com/kube-bind/kube-bind/pkg/bootstrap" +) + +//go:embed *.yaml +var ExampleBackendAssets embed.FS + +func BootstrapExampleBackend(t *testing.T, discoveryClient discovery.DiscoveryInterface, dynamicClient dynamic.Interface, batteriesIncluded sets.Set[string]) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + err := bootstrap.Bootstrap(ctx, discoveryClient, dynamicClient, batteriesIncluded, ExampleBackendAssets) + require.NoError(t, err) +} diff --git a/contrib/kcp/deploy/examples/sheriff.yaml b/contrib/kcp/deploy/examples/sheriff.yaml deleted file mode 100644 index dff34e843..000000000 --- a/contrib/kcp/deploy/examples/sheriff.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: wildwest.dev/v1alpha1 -kind: Sheriff -metadata: - name: sheriff -spec: - intent: "ride into the sunset" \ No newline at end of file diff --git a/contrib/kcp/deploy/examples/template-sheriffs.yaml b/contrib/kcp/deploy/examples/template-sheriffs.yaml deleted file mode 100644 index bd3a8e117..000000000 --- a/contrib/kcp/deploy/examples/template-sheriffs.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: APIServiceExportTemplate -metadata: - name: sheriffs -spec: - scope: Cluster - resources: - - group: wildwest.dev - versions: - - v1alpha1 - resource: sheriffs - permissionClaims: - - group: "" - resource: secrets - selector: - namedResources: - - name: sheriff-badge-credentials - - name: sheriff-jurisdiction-config - labelSelector: - matchLabels: - app: sheriff - security: high - - group: "" - resource: configmaps - selector: - namedResources: - - name: sheriff-jurisdiction-map - - name: sheriff-enforcement-rules - labelSelector: - matchLabels: - app: sheriff - component: enforcement - namespaces: - - name: sheriff-operations - - name: sheriff-intelligence \ No newline at end of file diff --git a/contrib/kcp/go.mod b/contrib/kcp/go.mod index a77882d9f..617d0bae2 100644 --- a/contrib/kcp/go.mod +++ b/contrib/kcp/go.mod @@ -139,7 +139,7 @@ require ( golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect diff --git a/contrib/kcp/go.sum b/contrib/kcp/go.sum index ee2da0009..69ff704ae 100644 --- a/contrib/kcp/go.sum +++ b/contrib/kcp/go.sum @@ -360,8 +360,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/contrib/kcp/test/e2e/kcp_test.go b/contrib/kcp/test/e2e/kcp_test.go index d5190ef30..691695bcd 100644 --- a/contrib/kcp/test/e2e/kcp_test.go +++ b/contrib/kcp/test/e2e/kcp_test.go @@ -35,7 +35,8 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" - boostrapdeploy "github.com/kube-bind/kube-bind/contrib/kcp/deploy" + kcpboostrapdeploy "github.com/kube-bind/kube-bind/contrib/kcp/deploy" + bootstrapdeploy "github.com/kube-bind/kube-bind/deploy/examples" kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2" "github.com/kube-bind/kube-bind/test/e2e/framework" ) @@ -111,14 +112,21 @@ func testKcpIntegration(t *testing.T, name string, scope kubebindv1alpha2.Inform files := []string{"examples/apiexport.yaml", "examples/apiresourceschema-cowboys.yaml", // namespaced "examples/apiresourceschema-sheriffs.yaml", // cluster scoped - "examples/template-cowboys.yaml", // template for cowboys - "examples/template-sheriffs.yaml", // template for sheriffs - "examples/collection-wildwest.yaml", } for _, f := range files { - data, err := boostrapdeploy.Examples.ReadFile(f) + data, err := kcpboostrapdeploy.Examples.ReadFile(f) require.NoError(t, err, "failed to read example file %s", f) + framework.ApplyManifest(t, providerCfg, data) + } + files = []string{ + "template-cowboys.yaml", // template for cowboys + "template-sheriffs.yaml", // template for sheriffs + "collection.yaml", + } + for _, f := range files { + data, err := bootstrapdeploy.Examples.ReadFile(f) + require.NoError(t, err, "failed to read example file %s", f) framework.ApplyManifest(t, providerCfg, data) } diff --git a/deploy/examples/apiresourceschema.yaml b/deploy/examples/apiresourceschema.yaml deleted file mode 100644 index aa8f1277e..000000000 --- a/deploy/examples/apiresourceschema.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: APIResourceSchema -metadata: - name: mangodbs.mangodb.com - labels: - kube-bind.io/exported: "true" -spec: - informerScope: Namespaced - group: mangodb.com - names: - kind: MangoDB - listKind: MangoDBList - plural: mangodbs - singular: mangodb - scope: Namespaced - versions: - - name: v1alpha1 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - tier: - type: string - enum: - - Dedicated - - Shared - default: Shared - status: - type: object - properties: - phase: - type: string - required: - - spec - subresources: - status: {} \ No newline at end of file diff --git a/deploy/examples/collection.yaml b/deploy/examples/collection.yaml index a456e1a06..21c0fc74e 100644 --- a/deploy/examples/collection.yaml +++ b/deploy/examples/collection.yaml @@ -4,5 +4,5 @@ metadata: name: all spec: templates: - - name: mangodb - - name: foo \ No newline at end of file + - name: cowboys + - name: sheriffs diff --git a/deploy/examples/cr-cowboy.yaml b/deploy/examples/cr-cowboy.yaml new file mode 100644 index 000000000..6471a73fc --- /dev/null +++ b/deploy/examples/cr-cowboy.yaml @@ -0,0 +1,23 @@ +apiVersion: wildwest.dev/v1alpha1 +kind: Cowboy +metadata: + name: billy-the-kid +spec: + intent: "Ride the range and protect the cattle" + weapons: + - name: colt-45-permit + - name: winchester-rifle-license +status: + result: "Ready to ride" +--- +apiVersion: v1 +kind: Secret +metadata: + name: colt-45-permit + labels: + app: cowboy + type: weapon +data: + serial_number: QzQ1LTEyMzQ1Ng== # "C45-123456" base64 encoded + permit_date: MTg4MS0wNC0xNQ== # "1881-04-15" base64 encoded + issued_by: VG9tYnN0b25lIE1hcnNoYWw= # "Tombstone Marshal" base64 encoded \ No newline at end of file diff --git a/deploy/examples/cr-sheriff.yaml b/deploy/examples/cr-sheriff.yaml new file mode 100644 index 000000000..a179eae02 --- /dev/null +++ b/deploy/examples/cr-sheriff.yaml @@ -0,0 +1,26 @@ +apiVersion: wildwest.dev/v1alpha1 +kind: Sheriff +metadata: + name: wyatt-earp +spec: + intent: "Keep the peace in Tombstone" + secretRefs: + - name: sheriff-badge-credentials + namespace: sheriff-operations + - name: sheriff-jurisdiction-config + namespace: sheriff-operations +status: + result: "Ready for duty" +--- +apiVersion: v1 +kind: Secret +metadata: + name: sheriff-badge-credentials + namespace: sheriff-operations + labels: + app: sheriff + security: high +data: + badge_number: IzEyMzQ1 # "#12345" base64 encoded + authority_level: aGlnaA== # "high" base64 encoded + jurisdiction: dG9tYnN0b25l # "tombstone" base64 encoded \ No newline at end of file diff --git a/deploy/examples/crd-cowboys.yaml b/deploy/examples/crd-cowboys.yaml new file mode 100644 index 000000000..893322d28 --- /dev/null +++ b/deploy/examples/crd-cowboys.yaml @@ -0,0 +1,60 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: cowboys.wildwest.dev + labels: + kube-bind.io/exported: "true" +spec: + group: wildwest.dev + names: + kind: Cowboy + listKind: CowboyList + plural: cowboys + singular: cowboy + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + description: Cowboy is part of the wild west + type: object + 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' + 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' + type: string + metadata: + type: object + spec: + description: CowboySpec holds the desired state of the Cowboy. + type: object + properties: + intent: + type: string + weapons: + type: array + description: "Array of references to Secrets containing weapon permits and licenses" + items: + type: object + properties: + name: + type: string + description: "Name of the referenced Secret" + required: + - name + status: + description: CowboyStatus communicates the observed state of the Cowboy. + type: object + properties: + result: + type: string + subresources: + status: {} \ No newline at end of file diff --git a/deploy/examples/crd-foo.yaml b/deploy/examples/crd-foo.yaml deleted file mode 100644 index 32dbcb06e..000000000 --- a/deploy/examples/crd-foo.yaml +++ /dev/null @@ -1,47 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: foos.bar.io - labels: - kube-bind.io/exported: "true" -spec: - group: bar.io - versions: - - name: v1alpha1 - served: true - storage: true - schema: - # schema used for validation - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - deploymentName: - type: string - replicas: - type: integer - minimum: 1 - maximum: 10 - status: - type: object - properties: - availableReplicas: - type: integer - phase: - type: string - enum: - - Pending - - Running - - Succeeded - - Failed - - Unknown - # subresources for the custom resource - subresources: - # enables the status subresource - status: {} - names: - kind: Foo - plural: foos - scope: Cluster diff --git a/deploy/examples/crd-mangodb.yaml b/deploy/examples/crd-mangodb.yaml deleted file mode 100644 index d6a62b688..000000000 --- a/deploy/examples/crd-mangodb.yaml +++ /dev/null @@ -1,40 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: mangodbs.mangodb.com - labels: - kube-bind.io/exported: "true" -spec: - group: mangodb.com - names: - kind: MangoDB - listKind: MangoDBList - plural: mangodbs - singular: mangodb - scope: Namespaced - versions: - - name: v1alpha1 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - tier: - type: string - enum: - - Dedicated - - Shared - default: Shared - status: - type: object - properties: - phase: - type: string - required: - - spec - subresources: - status: {} diff --git a/deploy/examples/crd-sheriffs.yaml b/deploy/examples/crd-sheriffs.yaml new file mode 100644 index 000000000..ad5440432 --- /dev/null +++ b/deploy/examples/crd-sheriffs.yaml @@ -0,0 +1,61 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: sheriffs.wildwest.dev + labels: + kube-bind.io/exported: "true" +spec: + group: wildwest.dev + names: + kind: Sheriff + listKind: SheriffList + plural: sheriffs + singular: sheriff + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + description: Sheriff is part of the wild west + type: object + 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' + 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' + type: string + metadata: + type: object + spec: + description: SheriffSpec holds the desired state of the Sheriff. + type: object + properties: + intent: + type: string + badge: + type: object + description: "Reference to a Secret containing sheriff badge credentials" + properties: + name: + type: string + description: "Name of the referenced Secret" + namespace: + type: string + description: "Namespace of the referenced Secret" + required: + - name + status: + description: SheriffStatus communicates the observed state of the Sheriff. + type: object + properties: + result: + type: string + subresources: + status: {} \ No newline at end of file diff --git a/deploy/examples/examples.go b/deploy/examples/examples.go new file mode 100644 index 000000000..31720fc19 --- /dev/null +++ b/deploy/examples/examples.go @@ -0,0 +1,41 @@ +/* +Copyright 2025 The Kube Bind Authors. + +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 examples + +import ( + "context" + "embed" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/discovery" + "k8s.io/client-go/dynamic" + + "github.com/kube-bind/kube-bind/pkg/bootstrap" +) + +//go:embed cr-*.yaml template-*.yaml collection.yaml +var Examples embed.FS + +func Bootstrap(t *testing.T, discoveryClient discovery.DiscoveryInterface, dynamicClient dynamic.Interface, batteriesIncluded sets.Set[string]) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + err := bootstrap.Bootstrap(ctx, discoveryClient, dynamicClient, batteriesIncluded, Examples) + require.NoError(t, err) +} diff --git a/deploy/examples/foo.yaml b/deploy/examples/foo.yaml deleted file mode 100644 index 916270e30..000000000 --- a/deploy/examples/foo.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: bar.io/v1alpha1 -kind: Foo -metadata: - name: test -spec: - deploymentName: test-foo - replicas: 2 \ No newline at end of file diff --git a/deploy/examples/mangodb.yaml b/deploy/examples/mangodb.yaml deleted file mode 100644 index 4c6b8d334..000000000 --- a/deploy/examples/mangodb.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: mangodb.com/v1alpha1 -kind: MangoDB -metadata: - name: my-first-mangodb-instance - namespace: default -spec: - tier: Dedicated -status: - phase: Pending \ No newline at end of file diff --git a/deploy/examples/servicenamespace-example.yaml b/deploy/examples/servicenamespace-example.yaml deleted file mode 100644 index fc4b82089..000000000 --- a/deploy/examples/servicenamespace-example.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: kube-bind.io/v1alpha1 -kind: APIServiceNamespace -metadata: - name: example -spec: {} diff --git a/contrib/kcp/deploy/examples/template-cowboys.yaml b/deploy/examples/template-cowboys.yaml similarity index 50% rename from contrib/kcp/deploy/examples/template-cowboys.yaml rename to deploy/examples/template-cowboys.yaml index dccca8910..70bdb1649 100644 --- a/contrib/kcp/deploy/examples/template-cowboys.yaml +++ b/deploy/examples/template-cowboys.yaml @@ -13,20 +13,8 @@ spec: - group: "" resource: secrets selector: - namedResources: - - name: cowboy-credentials - - name: cowboy-config labelSelector: matchLabels: app: cowboy - env: production - - group: "" - resource: configmaps - selector: - namedResources: - - name: cowboy-settings - - name: cowboy-environment - labelSelector: - matchLabels: - app: cowboy - component: config \ No newline at end of file + namespaces: + - name: wild-west diff --git a/deploy/examples/template-foo.yaml b/deploy/examples/template-foo.yaml deleted file mode 100644 index 80cefc53c..000000000 --- a/deploy/examples/template-foo.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: APIServiceExportTemplate -metadata: - name: foo -spec: - scope: Cluster - resources: - - group: bar.io - versions: - - v1alpha1 - resource: foos - permissionClaims: - - group: "" - resource: configmaps - selector: - namedResources: - - name: named-configmap-only - namespace: foo-secrets-ns - - group: "" - resource: secrets - selector: - labelSelector: - matchLabels: - app: secrets - namedResources: - - name: test-secret - namespace: foo-secrets-ns - - name: named-secret-1 - namespace: foo-secrets-ns - - name: named-secret-2 - namespace: foo-secrets-ns - namespaces: - - name: foo-secrets-ns \ No newline at end of file diff --git a/deploy/examples/template-mangodb.yaml b/deploy/examples/template-mangodb.yaml deleted file mode 100644 index 51e182394..000000000 --- a/deploy/examples/template-mangodb.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: kube-bind.io/v1alpha2 -kind: APIServiceExportTemplate -metadata: - name: mangodb -spec: - scope: Namespaced - resources: - - group: mangodb.com - versions: - - v1alpha1 - resource: mangodbs - permissionClaims: - - group: "" - resource: "secrets" - selector: - labelSelector: - matchLabels: - app: "mangodb" - namedResources: - - name: "mangodb-credentials" - namespace: "mangodb-namespace" - namespaces: - - name: mangodb-namespace \ No newline at end of file diff --git a/contrib/kcp/deploy/examples/apiserviceexport-cluster.yaml b/deploy/examples/template-sheriffs.yaml similarity index 56% rename from contrib/kcp/deploy/examples/apiserviceexport-cluster.yaml rename to deploy/examples/template-sheriffs.yaml index 14fec2669..7e01fb3e9 100644 --- a/contrib/kcp/deploy/examples/apiserviceexport-cluster.yaml +++ b/deploy/examples/template-sheriffs.yaml @@ -1,18 +1,20 @@ apiVersion: kube-bind.io/v1alpha2 -kind: APIServiceExportRequest +kind: APIServiceExportTemplate metadata: - name: sheriffs.wildwest.dev + name: sheriffs spec: + scope: Cluster resources: - group: wildwest.dev - resource: sheriffs - versions: + versions: - v1alpha1 + resource: sheriffs permissionClaims: - group: "" - resource: configmaps + resource: secrets selector: labelSelector: matchLabels: - app: wildwest -status: {} + app: sheriff + namespaces: + - name: sheriff-operations diff --git a/docs/content/developers/dev-environments.md b/docs/content/developers/dev-environments.md index 36d105e8f..d4a068816 100644 --- a/docs/content/developers/dev-environments.md +++ b/docs/content/developers/dev-environments.md @@ -35,13 +35,7 @@ All the instructions assume you have already cloned the kube-bind repository and ## Preparation - 1. Start dex - - ```bash - make run-dex - ``` - - 2. Start kcp + 1. Start kcp ```bash make run-kcp @@ -62,14 +56,11 @@ All the instructions assume you have already cloned the kube-bind repository and ./bin/backend \ --multicluster-runtime-provider kcp \ --server-url=$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath="{.status.endpoints[0].url}") \ - --oidc-issuer-client-secret=ZXhhbXBsZS1hcHAtc2VjcmV0 \ - --oidc-issuer-client-id=kube-bind \ - --oidc-issuer-url=http://127.0.0.1:5556/dex \ + --oidc-issuer-url=http://127.0.0.1:8080/oidc \ --oidc-callback-url=http://127.0.0.1:8080/api/callback \ + --oidc-type=embedded \ --pretty-name="BigCorp.com" \ --namespace-prefix="kube-bind-" \ - --cookie-signing-key=bGMHz7SR9XcI9JdDB68VmjQErrjbrAR9JdVqjAOKHzE= \ - --cookie-encryption-key=wadqi4u+w0bqnSrVFtM38Pz2ykYVIeeadhzT34XlC1Y= \ --schema-source apiresourceschemas \ --consumer-scope=cluster ``` @@ -108,9 +99,9 @@ All the instructions assume you have already cloned the kube-bind repository and kubectl apply -f contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml kubectl kcp bind apiexport root:provider:cowboys-stable - kubectl apply -f contrib/kcp/deploy/examples/template-cowboys.yaml - kubectl apply -f contrib/kcp/deploy/examples/template-sheriffs.yaml - kubectl apply -f contrib/kcp/deploy/examples/collection-wildwest.yaml + kubectl apply -f deploy/examples/template-cowboys.yaml + kubectl apply -f deploy/examples/template-sheriffs.yaml + kubectl apply -f deploy/examples/collection.yaml ``` 8. Get LogicalCluster: @@ -118,7 +109,7 @@ All the instructions assume you have already cloned the kube-bind repository and ```bash kubectl get logicalcluster # NAME PHASE URL AGE - # cluster Ready https://192.168.2.166:6443/clusters/1y7tqtsucxaekmqu + # cluster Ready https://192.168.2.166:6443/clusters/2myqz7lt9i0u5kzb ``` ## Consumer @@ -134,7 +125,7 @@ All the instructions assume you have already cloned the kube-bind repository and 10. Bind the thing: ```bash - ./bin/kubectl-bind login http://127.0.0.1:8080 --cluster + ./bin/kubectl-bind login http://127.0.0.1:8080 --cluster 2myqz7lt9i0u5kzb ./bin/kubectl-bind --dry-run -o yaml > apiserviceexport.yaml # Extract secret for binding process. Note that secret name is not the same as output from command above. Check secret @@ -156,74 +147,21 @@ All the instructions assume you have already cloned the kube-bind repository and ./bin/konnector --lease-namespace default --kubeconfig .kcp/consumer.kubeconfig ``` - Optionally add second consumer to test - + Create example resources in consumer: ```bash - cp .kcp/admin.kubeconfig .kcp/consumer2.kubeconfig - export KUBECONFIG=.kcp/consumer2.kubeconfig - kubectl ws use :root - kubectl ws create consumer2 --enter - - ./bin/kubectl-bind http://127.0.0.1:8080/clusters/2vgrh380y0cq38du/exports --dry-run -o yaml > apiserviceexport2.yaml - - kubectl get secrets -n kube-bind -o jsonpath='{.items[0].data.kubeconfig}' | base64 -d > remote2.kubeconfig - - ./bin/kubectl-bind apiservice -v 6 --remote-kubeconfig remote2.kubeconfig -f apiserviceexport2.yaml --skip-konnector --remote-namespace "$(yq '.contexts[0].context.namespace' remote2.kubeconfig)" - - ./bin/konnector --lease-namespace default --kubeconfig .kcp/consumer2.kubeconfig --server-address :8091 - ``` - - This will keep running, so switch to a new terminal. - - ## Testing - - Create objects: - ``` - export KUBECONFIG=.kcp/consumer.kubeconfig - kubectl apply -f contrib/kcp/deploy/examples/cowboy.yaml - kubectl apply -f contrib/kcp/deploy/examples/sheriff.yaml - ``` - - ## Debug - - ```bash - - cp .kcp/admin.kubeconfig .kcp/debug.kubeconfig - export KUBECONFIG=.kcp/debug.kubeconfig - k ws use :root:kube-bind - - k -s "$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath='{.status.endpoints[0].url}')/clusters/*" api-resources - - k -s "$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath='{.status.endpoints[0].url}')/clusters/*" get crd - - namespace=$(yq '.contexts[0].context.namespace' remote.kubeconfig) - - # some claimed objects - - kubectl create cm provider -n "$namespace-default" - kubectl label cm provider app=wildwest -n "$namespace-default" - - kubectl create cm consumer -n default - kubectl label cm consumer app=wildwest -n default - - kubectl create secret generic provider-secret - kubectl label secret provider-secret app=wildwest - - kubectl create namespace bob - kubectl create secret generic wildwest-secrets1 -n bob - kubectl label secret wildwest-secrets1 app=wildwest -n bob + kubectl apply -f deploy/examples/cr-cowboy.yaml + kubectl apply -f deploy/examples/cr-sheriff.yaml ``` === "Kind" This guide will walk you through setting up kube-bind between two Kubernetes clusters, where + * **Provider cluster**: + * Deploys kube-bind/backend + * Provides kube-bind compatible backend for Sheriffs resources - * **Backend cluster**: - * Deploys dex, cert-manager and kube-bind/backend - * Provides kube-bind compatible backend for MangoDB resources - - * **App cluster**: - * Provides an application consuming MangoDBs + * **Consumer cluster**: + * Provides an application consuming Sheriffs and Cowboys resources from the Provider cluster This guide works best on Linux. macOS and Windows users may need to adjust some commands accordingly. @@ -234,8 +172,8 @@ All the instructions assume you have already cloned the kube-bind repository and * [`kind`](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) * [`kubectl`](https://kubernetes.io/docs/tasks/tools/) * [`kubectl-bind`](https://github.com/kube-bind/kube-bind/releases/latest) (a kubectl plugin) - * [`helm`](https://helm.sh/docs/intro/quickstart/) * [`jq`](https://jqlang.github.io/jq/download/) + * port 8080 and 6443 open on your localhost To install `kubectl-bind` plugin, please download the archive for your platform from the link above, extract it, and place the `kubectl-bind` executable in your system's `$PATH`. @@ -248,296 +186,82 @@ All the instructions assume you have already cloned the kube-bind repository and > > See the [kind documentation](https://kind.sigs.k8s.io/docs/user/known-issues/#pod-errors-due-to-too-many-open-files) for more details. - ## Provider cluster - - The provider cluster we'll prepare in this section will provide a kube-bind compatible backend that will provide a controller for a demo resource "MangoDB" we'll consume in another cluster later. - - > What is MangoDB? It is just an example CRD to demonstrate kube-bind's capabilities and testing, without any workloads. See its definition in [/test/e2e/bind/fixtures/provider/crd-mangodb.yaml](/test/e2e/bind/fixtures/provider/crd-mangodb.yaml). - - ### Step one: create the Backend cluster - - First, stash the host's external IP in a variable as we're going to use it often: - - ```sh - # Linux - export BACKEND_HOST_IP="$(hostname -i | cut -d' ' -f1)" - ``` - - Create a Kind cluster named "backend": - - ```sh - cat << EOF_BackendClusterDefinition | kind create cluster --config=- - apiVersion: kind.x-k8s.io/v1alpha4 - kind: Cluster - name: backend - networking: - apiServerAddress: ${BACKEND_HOST_IP} - nodes: - - role: control-plane - extraPortMappings: - # MangoDB export endpoint - - containerPort: 30080 - hostPort: 8080 - protocol: TCP - # dex endpoint - - containerPort: 30556 - hostPort: 5556 - protocol: TCP - EOF_BackendClusterDefinition - ``` - - > Note: the port mappings will become clear later on, but in general this setup is solely specific to how Kind exposes ports of its nodes on the host. Specifically, we're exposing ports from containers through NodePort services on Kind's nodes, and to make these ports available on the host we need to map them to host's ports through `extraPortMappings`. + ## Setup - ### Step two: deploy an identity provider + run `kubectl bind dev create`, which will automatically create two Kind clusters (provider and consumer), deploy kube-bind backend in the provider cluster, and print required commands to bind the consumer cluster to the provider. - kube-bind relies on OAuth2 for securely authenticating consumer and producer clusters. There are many ways to handle that in Kubernetes, for example with [dex IDP](https://github.com/dexidp/dex). It depends on cert-manager, which we'll deploy first: + This command will create two Kind clusters named `kind-provider` and `kind-consumer`, set up a Docker network for them to communicate, and install kube-bind backend in the provider cluster and establish right `hostAlias` entries for communication between clusters. ```sh - helm repo add jetstack https://charts.jetstack.io - helm install \ - --create-namespace \ - --namespace pki \ - --version v1.16.2 \ - --set crds.enabled=true \ - cert-manager jetstack/cert-manager + kubectl bind dev create ``` - And now let's deploy dex: + You should see output similar to this: ```sh - helm repo add dex https://charts.dexidp.io - cat << EOF_DEXDeploymentConfig | - config: - staticClients: - - id: kube-bind - redirectURIs: - - 'http://${BACKEND_HOST_IP}:8080/api/callback' - name: 'Kube Bind' - secret: ZXhhbXBsZS1hcHAtc2VjcmV0 - - issuer: http://${BACKEND_HOST_IP}:5556/dex - - storage: - type: kubernetes - config: - inCluster: true - - web: - http: 127.0.0.1:5556 - - telemetry: - http: 127.0.0.1:5558 - - grpc: - addr: 127.0.0.1:5557 - - connectors: - - type: mockCallback - id: mock - name: Example - - enablePasswordDB: true - staticPasswords: - - email: "admin@example.com" - hash: "\$2a\$10\$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" - username: "admin" - userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" - EOF_DEXDeploymentConfig - helm install \ - --create-namespace \ - --namespace idp \ - --set service.type=NodePort \ - --set service.ports.http.nodePort=30556 \ - dex dex/dex \ - -f - - ``` - - ### Step three: deploy the MangoDB kube-bind backend + kubectl bind dev create 09:59:12 + ๐Ÿงช EXPERIMENTAL: kube-bind dev command is in preview + ๐Ÿ“ฆ Requirements: Docker must be installed and running + Warning: Could not automatically add host entry. Please run: + echo '127.0.0.1 kube-bind.dev.local' | sudo tee -a /etc/hosts + Kind cluster kind-provider already exists, skipping creation + Wrote kubeconfig kind-provider.kubeconfig + Helm chart installed successfully + Provider cluster IP address: 192.168.155.2 + Creating kind cluster kind-consumer with network kube-bind-dev + Kind cluster kind-consumer created + Wrote kubeconfig kind-consumer.kubeconfig + ๐Ÿš€ kube-bind dev environment is ready! - Now we'll deploy a kube-bind-compatible backend for MangoDB. Let's start with kube-bind CRDs: - - ```sh - kubectl apply -f deploy/crd - ``` + - Provider cluster kubeconfig: kind-provider.kubeconfig + - Consumer cluster kubeconfig: kind-consumer.kubeconfig + - kube-bind server URL: http://kube-bind.dev.local:8080 + - Next steps: + 1. Run login to authenticate to the provider cluster: - And now CRDs for MangoDB and related resources to be provided by the backend: - ```sh - kubectl apply -f deploy/examples/crd-mangodb.yaml - kubectl apply -f deploy/examples/crd-foo.yaml - kubectl apply -f deploy/examples/template-mangodb.yaml - kubectl apply -f deploy/examples/template-foo.yaml - kubectl apply -f deploy/examples/collection.yaml - ``` + kubectl bind login http://kube-bind.dev.local:8080 - To set up the MangoDB backend we'll need: - * ServiceAccount and ClusterRoleBinding for kube-bind's user, - * Deployment that runs the MangoDB backend - * Service that exposes the backend's address + 2. Run bind to bind an API service from the provider to the consumer cluster: - ```sh - kubectl create namespace backend - # This is the address that will be used when generating kubeconfigs the App cluster, - # and so we need to be able to reach it from outside. - export BACKEND_KUBE_API_EXTERNAL_ADDRESS="$(kubectl config view --minify -o json | jq '.clusters[0].cluster.server' -r)" - # For demo example let's just bind "cluster-admin" ClusterRole to backend's "default" ServiceAccount. - kubectl create clusterrolebinding backend-admin --clusterrole cluster-admin --serviceaccount backend:default - # Create a new Deployment for the MangoDB backend. - kubectl --namespace backend \ - create deployment mangodb \ - --image ghcr.io/kube-bind/backend:main \ - --port 8080 \ - -- /bin/backend \ - --listen-address 0.0.0.0:8080 \ - --external-address "${BACKEND_KUBE_API_EXTERNAL_ADDRESS}" \ - --oidc-issuer-client-secret=ZXhhbXBsZS1hcHAtc2VjcmV0 \ - --oidc-issuer-client-id=kube-bind \ - --oidc-issuer-url=http://${BACKEND_HOST_IP}:5556/dex \ - --oidc-callback-url=http://${BACKEND_HOST_IP}:8080/api/callback \ - --pretty-name="BigCorp.com" \ - --namespace-prefix="kube-bind-" \ - --cookie-signing-key=bGMHz7SR9XcI9JdDB68VmjQErrjbrAR9JdVqjAOKHzE= \ - --cookie-encryption-key=wadqi4u+w0bqnSrVFtM38Pz2ykYVIeeadhzT34XlC1Y= - # Expose mangodb's container port 8080 as a NodePort at 30080. We've already configured - # Kind to expose 30800 at host's 8080. - kubectl --namespace backend \ - create service nodeport mangodb \ - --tcp 8080 \ - --node-port 30080 + KUBECONFIG=kind-consumer.kubeconfig kubectl bind --konnector-host-alias 192.168.155.2:kube-bind.dev.local ``` - And that's really all there's to it. After that, you should see a kubectl output similar to this: - - ```shell - $ kubectl --namespace backend get all - NAME READY STATUS RESTARTS AGE - pod/mangodb-6ff44cbbf-x7cjm 1/1 Running 0 100s + !!! note + Note /etc/hosts modification and 2 commands to run to bind the consumer cluster. - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - service/mangodb NodePort 10.96.10.212 8080:30080/TCP 100s + ## Login to Provider cluster - NAME READY UP-TO-DATE AVAILABLE AGE - deployment.apps/mangodb 1/1 1 1 100s + This should give you UI authorization screen. - NAME DESIRED CURRENT READY AGE - replicaset.apps/mangodb-6ff44cbbf 1 1 1 100s - ``` - - ## Consumer App cluster - - The App cluster will consume MangoDB CRs provided by the Backend. - - ### Step one: create the App cluster - - Again, let's start by stashing the host's external IP in a variable as we're going to use it often (possibly the same one as for the Backend cluster): - - ```sh - export APP_HOST_IP="$(hostname -i | cut -d' ' -f1)" - ``` - - Create a Kind cluster named "app": - - ```sh - cat << EOF_AppClusterDefinition | kind create cluster --config=- - apiVersion: kind.x-k8s.io/v1alpha4 - kind: Cluster - name: app - networking: - apiServerAddress: ${APP_HOST_IP} - EOF_AppClusterDefinition - ``` - - ### Binding MangoDB backend - - Now we'll bring in MangoDB CRDs from the Backend cluster (you can run `kubectl get crds` to see there are none yet): - - ```sh - kubectl bind login http://${BACKEND_HOST_IP}:8080 - kubectl bind - ๐ŸŒ Opening kube-bind UI in your browser... - http://127.0.0.1:8080?cluster_id=7yw1thtocnvdhf74&redirect_url=http%3A%2F%2F127.0.0.1%3A63385%2Fcallback&session_id=UHKJVXR3VGT73VUUVVV7E7ERB5 - - Waiting for binding completion from UI... - (Press Ctrl+C to cancel) + ```bash + kubectl bind login http://kube-bind.dev.local:8080 ``` - The client is now waiting for you to visit the address similar to the one displayed in the output above. After completing the steps to create an OAuth2 token, it is then used by the kube-bind backend to pass the ServiceAccount's kubeconfig (in the Backend cluster) to the App cluster securely: - 1. on the "Log in to dex" landing page, select "Log in with Example", - 2. on the "Grant Access" page, click the "Grant Access" button, - 3. lastly, click "Bind" when the page displays the mangodb resource. + # Bind first provider API service - Go back to the terminal where `kubectl bind` command was run, and you should see the following output: - ``` - ๐Ÿ”‘ Successfully authenticated to http://${BACKEND_HOST_IP}:8080/export - ๐Ÿ”’ Created secret kube-bind/kubeconfig-x9bd5 for host https://${BACKEND_HOST_IP}:34595, namespace kube-bind-gfsqn - ๐Ÿš€ Executing: kubectl bind apiservice --remote-kubeconfig-namespace kube-bind --remote-kubeconfig-name kubeconfig-x9bd5 -f - - โœจ Use "-o yaml" and "--dry-run" to get the APIServiceExportRequest. - and pass it to "kubectl bind apiservice" directly. Great for automation. - ๐Ÿš€ Deploying konnector v0.4.6 to namespace kube-bind. - Waiting for the konnector to be ready.............. - โœ… Created APIServiceBinding mangodbs.mangodb.com - - NAME PROVIDER READY MESSAGE AGE - apiservicebinding.kube-bind.io/mangodbs.mangodb.com False Pending 0s + ```bash + KUBECONFIG=kind-consumer.kubeconfig kubectl bind --konnector-host-alias 192.168.155.2:kube-bind.dev.local ``` - ### Step two: demo time! - - Let's see if we have CRDs for the MangoDB resource: - - ```sh - $ kubectl get crds + Now in the consumer cluster you should see these CRDs: + + ```bash + kubectl get crd 10:10:56 NAME CREATED AT - apiservicebindings.kube-bind.io 2024-12-19T08:46:13Z - mangodbs.mangodb.com 2024-12-19T08:46:17Z + apiservicebindings.kube-bind.io 2025-11-12T08:10:48Z + mangodbs.mangodb.com 2025-11-12T08:10:56Z ``` - We do! Now create a CR for it: - - ```sh - kubectl create -f - << EOF_MangoDBDefinition - apiVersion: mangodb.com/v1alpha1 - kind: MangoDB - metadata: - name: my-db - spec: - tokenSecret: my-secret - region: eu-west-1 - tier: Shared - EOF_MangoDBDefinition - - kubectl describe mangodb my-db - ``` + Try creating an example MangoDB resource and observe it being synced to provider clusters: - And finally, switch to the backend cluster and see that the CR is mirrored there: - ```sh - $ kubectl config use-context kind-backend - Switched to context "kind-backend". - # Your "kube-bind--default" will be different. - $ kubectl -n kube-bind-rp2s9-default describe mangodb my-db - Name: my-db - Namespace: kube-bind-rp2s9-default - Labels: - Annotations: - API Version: mangodb.com/v1alpha1 - Kind: MangoDB - Metadata: - Creation Timestamp: 2024-12-19T08:48:07Z - Generation: 1 - Resource Version: 1564 - UID: bed9f6d6-79d5-4535-8b20-690470b23378 - Spec: - Backup: false - Region: eu-west-1 - Tier: Shared - Token Secret: my-secret - Events: + ```bash + kubectl bind dev example | kubectl create -f - + KUBECONFIG=kind-consumer.kubeconfig kubectl get mangodbs.mangodb.com + KUBECONFIG=kind-provider.kubeconfig kubectl get mangodbs.mangodb.com ``` - ### Step three: clean up - - Once you're done, you may clean up the setup simply by deleting the two kind clusters: - + ## Cleanup + ```sh - kind delete cluster --name backend - kind delete cluster --name app + kind bind dev delete ``` diff --git a/docs/content/setup/kcp-setup.md b/docs/content/setup/kcp-setup.md index 23e610477..7a110845b 100644 --- a/docs/content/setup/kcp-setup.md +++ b/docs/content/setup/kcp-setup.md @@ -19,94 +19,53 @@ The kcp provider integrates kube-bind with [kcp](https://github.com/kcp-dev/kcp) ## Prerequisites - [kcp](https://github.com/kcp-dev/kcp) instance running and accessible -- [dex](https://github.com/dexidp/dex) for OIDC authentication - kube-bind binaries built (`make build`) ## Setup Steps -### 1. Start kcp +1. Start kcp ```bash make run-kcp ``` -### 2. Start Dex OIDC Provider - -Clone and configure dex: - -```bash -git clone https://github.com/dexidp/dex.git -cd dex && make build -``` - -Configure dex (`examples/config-dev.yaml`): - -```yaml -staticClients: -- id: kube-bind - redirectURIs: - - 'http://127.0.0.1:8080/callback' - name: 'Kube Bind' - secret: ZXhhbXBsZS1hcHAtc2VjcmV0 -``` - -Start dex: - -```bash -./bin/dex serve examples/config-dev.yaml -``` - -### 3. Bootstrap kcp - -Create the kube-bind provider workspace and APIExport: +## Backend +2. Bootstrap kcp: ```bash cp .kcp/admin.kubeconfig .kcp/backend.kubeconfig export KUBECONFIG=.kcp/backend.kubeconfig ./bin/kcp-init --kcp-kubeconfig $KUBECONFIG ``` - -### 4. Start Backend with kcp Provider - -Switch to the kube-bind workspace: - -```bash -kubectl ws use :root:kube-bind +3. Run the backend: ``` +k ws use :root:kube-bind -Start the backend with kcp provider: - -```bash ./bin/backend \ --multicluster-runtime-provider kcp \ --server-url=$(kubectl get apiexportendpointslice kube-bind.io -o jsonpath="{.status.endpoints[0].url}") \ - --oidc-issuer-client-secret=ZXhhbXBsZS1hcHAtc2VjcmV0 \ - --oidc-issuer-client-id=kube-bind \ - --oidc-issuer-url=http://127.0.0.1:5556/dex \ - --oidc-callback-url=http://127.0.0.1:8080/callback \ --pretty-name="BigCorp.com" \ + --oidc-type=embedded \ + --oidc-issuer-url=http://127.0.0.1:8080/oidc \ + --oidc-callback-url=http://127.0.0.1:8080/api/callback \ --namespace-prefix="kube-bind-" \ - --cookie-signing-key=bGMHz7SR9XcI9JdDB68VmjQErrjbrAR9JdVqjAOKHzE= \ - --cookie-encryption-key=wadqi4u+w0bqnSrVFtM38Pz2ykYVIeeadhzT34XlC1Y= \ - --schema-source apiresourceschemas + --schema-source apiresourceschemas \ --consumer-scope=cluster ``` -### 5. Create Provider Workspace +This process will keep running, so open a new terminal. -Create a provider workspace for hosting services: +## Provider +4. Copy the kubeconfig to the provider and create provider workspace: ```bash cp .kcp/admin.kubeconfig .kcp/provider.kubeconfig export KUBECONFIG=.kcp/provider.kubeconfig -kubectl ws use :root -kubectl ws create provider --enter +k ws use :root +kubectl create-workspace provider --enter ``` -### 6. Bind APIExport to Provider - -Bind the kube-bind APIExport to the provider workspace: - +5. Bind the APIExport to the provider workspace ```bash kubectl kcp bind apiexport root:kube-bind:kube-bind.io \ --accept-permission-claim clusterrolebindings.rbac.authorization.k8s.io \ @@ -121,38 +80,29 @@ kubectl kcp bind apiexport root:kube-bind:kube-bind.io \ --accept-permission-claim apiresourceschemas.apis.kcp.io ``` -### 7. Create Example Resources - -Deploy example APIExport and APIResourceSchemas: - +6. Create CRD in provider: ```bash -kubectl create -f contrib/kcp/deploy/examples/apiexport.yaml -kubectl create -f contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml -kubectl create -f contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml - -# Enable recursive binding +kubectl apply -f contrib/kcp/deploy/examples/apiexport.yaml +kubectl apply -f contrib/kcp/deploy/examples/apiresourceschema-cowboys.yaml +kubectl apply -f contrib/kcp/deploy/examples/apiresourceschema-sheriffs.yaml kubectl kcp bind apiexport root:provider:cowboys-stable -# Create templates and catalog -kubectl create -f contrib/kcp/deploy/examples/template-cowboys.yaml -kubectl create -f contrib/kcp/deploy/examples/template-sheriffs.yaml -kubectl create -f contrib/kcp/deploy/examples/collection-wildwest.yaml +kubectl apply -f deploy/examples/template-cowboys.yaml +kubectl apply -f deploy/examples/template-sheriffs.yaml +kubectl apply -f deploy/examples/collection.yaml ``` -### 8. Get Logical Cluster Information - -Retrieve the logical cluster URL for consumer setup: +7. Get LogicalCluster: ```bash kubectl get logicalcluster # NAME PHASE URL AGE -# cluster Ready https://192.168.2.166:6443/clusters/2xh2v3gzjhn4tmve +# cluster Ready https://192.168.2.166:6443/clusters/2ocmmccjkme8bof4 ``` -## Consumer Setup - -### 1. Create Consumer Workspace +## Consumer +8. Now we gonna initiate consumer: ```bash cp .kcp/admin.kubeconfig .kcp/consumer.kubeconfig export KUBECONFIG=.kcp/consumer.kubeconfig @@ -160,26 +110,34 @@ kubectl ws use :root kubectl ws create consumer --enter ``` -### 2. Perform Binding - -Generate the APIServiceExport YAML: +9. Bind the thing: ```bash -./bin/kubectl-bind login http://127.0.0.1:8080 --cluster -./bin/kubectl-bind --skip-konnector -``` +./bin/kubectl-bind login http://127.0.0.1:8080 --cluster 2ocmmccjkme8bof4 +./bin/kubectl-bind --dry-run -o yaml > apiserviceexport.yaml -### 3. Start Konnector +# Extract secret for binding process. Note that secret name is not the same as output from command above. Check secret +# name by running `kubectl get secret -n kube-bind` +kubectl get secrets -n kube-bind -o jsonpath='{.items[0].data.kubeconfig}' | base64 -d > remote.kubeconfig -```bash -export KUBECONFIG=.kcp/consumer.kubeconfig -go run ./cmd/konnector/ --lease-namespace default +namespace=$(yq '.contexts[0].context.namespace' remote.kubeconfig) + +./bin/kubectl-bind apiservice -v 6 --remote-kubeconfig remote.kubeconfig -f apiserviceexport.yaml --skip-konnector --remote-namespace "$namespace" ``` -### 4. Test the Setup +This will keep running, so switch to a new terminal. -Create example resources: +### Consumer Konnector + +Start konnector: ```bash -kubectl apply -f contrib/kcp/deploy/examples/cowboy.yaml +./bin/konnector --lease-namespace default --kubeconfig .kcp/consumer.kubeconfig ``` + +# Create an instance + +```bash +kubectl apply -f deploy/examples/cr-cowboy.yaml +kubectl apply -f deploy/examples/cr-sheriff.yaml +``` \ No newline at end of file diff --git a/docs/generators/cli-doc/go.mod b/docs/generators/cli-doc/go.mod index 66354f1d1..e9a6d9473 100644 --- a/docs/generators/cli-doc/go.mod +++ b/docs/generators/cli-doc/go.mod @@ -80,7 +80,7 @@ require ( github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.12 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -104,7 +104,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rubenv/sql-migrate v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect @@ -126,7 +126,7 @@ require ( golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect diff --git a/docs/generators/cli-doc/go.sum b/docs/generators/cli-doc/go.sum index 06f58a591..729e6e6d6 100644 --- a/docs/generators/cli-doc/go.sum +++ b/docs/generators/cli-doc/go.sum @@ -198,8 +198,9 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= @@ -272,8 +273,9 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnA github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o= @@ -394,8 +396,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -414,7 +416,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= diff --git a/go.mod b/go.mod index c1bb7a191..d18962adc 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ replace ( require ( github.com/coreos/go-oidc/v3 v3.16.0 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dexidp/dex/api/v2 v2.3.0 github.com/evanphx/json-patch/v5 v5.9.11 github.com/golang-jwt/jwt/v5 v5.3.0 @@ -65,6 +64,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -140,7 +140,7 @@ require ( golang.org/x/mod v0.26.0 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect diff --git a/go.sum b/go.sum index 2a7bb6551..1cf4c492f 100644 --- a/go.sum +++ b/go.sum @@ -356,8 +356,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=