From 6d63aae185ee6e72068cb1ce0afdcbfd76d4ce4e Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Thu, 5 Sep 2024 15:20:30 -0400 Subject: [PATCH 01/11] add admin component --- admin/Dockerfile | 13 ++ admin/go.mod | 55 ++++++++ admin/go.sum | 192 +++++++++++++++++++++++++++ admin/main.go | 31 +++++ admin/pkg/admin/admin.go | 63 +++++++++ admin/pkg/admin/adminResourceList.go | 156 ++++++++++++++++++++++ admin/pkg/admin/const.go | 17 +++ admin/pkg/admin/ocm.go | 82 ++++++++++++ admin/pkg/admin/routes.go | 41 ++++++ 9 files changed, 650 insertions(+) create mode 100644 admin/Dockerfile create mode 100644 admin/go.mod create mode 100644 admin/go.sum create mode 100644 admin/main.go create mode 100644 admin/pkg/admin/admin.go create mode 100644 admin/pkg/admin/adminResourceList.go create mode 100644 admin/pkg/admin/const.go create mode 100644 admin/pkg/admin/ocm.go create mode 100644 admin/pkg/admin/routes.go diff --git a/admin/Dockerfile b/admin/Dockerfile new file mode 100644 index 000000000..760793dd9 --- /dev/null +++ b/admin/Dockerfile @@ -0,0 +1,13 @@ +# Base and builder image will need to be replaced by Fips compliant one +FROM --platform=${TARGETPLATFORM:-linux/amd64} mcr.microsoft.com/oss/go/microsoft/golang:1.22-fips-cbl-mariner2.0@sha256:04ef70d7877189fcaafb649a442c43f9666a5ecf5b05c40ca0bfeddeec531efb as builder + +WORKDIR /app +ADD archive.tar.gz . +# https://github.com/microsoft/go/tree/microsoft/main/eng/doc/fips#build-option-to-require-fips-mode +ENV CGO_ENABLED=1 GOFLAGS='-tags=requirefips' +RUN cd admin && make admin + +FROM --platform=${TARGETPLATFORM:-linux/amd64} mcr.microsoft.com/cbl-mariner/distroless/base:2.0-nonroot@sha256:748adcb84f1132a27fd31b5cbaeaf2ff373d795babf35107dc6af05fab196ffc +WORKDIR / +COPY --from=builder /app/admin/aro-hcp-admin . +ENTRYPOINT ["/aro-hcp-admin"] \ No newline at end of file diff --git a/admin/go.mod b/admin/go.mod new file mode 100644 index 000000000..f6c1d02a8 --- /dev/null +++ b/admin/go.mod @@ -0,0 +1,55 @@ +module github.com/Azure/ARO-HCP/admin + +go 1.22.2 + +require ( + github.com/Azure/ARO-HCP/internal v0.0.0-20240905143746-fba3667d52ff + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 + github.com/openshift-online/ocm-sdk-go v0.1.438 + github.com/openshift/api v0.0.0-20240429104249-ac9356ba1784 +) + +require ( + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/glog v1.2.2 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_golang v1.20.2 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.30.0 // indirect + k8s.io/apimachinery v0.30.0 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect +) diff --git a/admin/go.sum b/admin/go.sum new file mode 100644 index 000000000..482aaa9b3 --- /dev/null +++ b/admin/go.sum @@ -0,0 +1,192 @@ +github.com/Azure/ARO-HCP/internal v0.0.0-20240905143746-fba3667d52ff h1:evP2JESht+FsLV81Z7sbuk+AgBqHkxySpGA9W35k0jE= +github.com/Azure/ARO-HCP/internal v0.0.0-20240905143746-fba3667d52ff/go.mod h1:smeRaQ7axK9o5KK0EfTxRdpKEXtEGtUQZvQvD2YnhVY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +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/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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/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= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/itchyny/gojq v0.12.7 h1:hYPTpeWfrJ1OT+2j6cvBScbhl0TkdwGM4bc66onUSOQ= +github.com/itchyny/gojq v0.12.7/go.mod h1:ZdvNHVlzPgUf8pgjnuDTmGfHA/21KoutQUJ3An/xNuw= +github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= +github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +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/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= +github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/openshift-online/ocm-sdk-go v0.1.438 h1:tsLCCUzbLCTL4RZG02y9RuopmGCXp2cjxqhdyCutdes= +github.com/openshift-online/ocm-sdk-go v0.1.438/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= +github.com/openshift/api v0.0.0-20240429104249-ac9356ba1784 h1:SmOZFMxuAH4d1Cj7dOftVyo4Wg/mEC4pwz6QIJJsAkc= +github.com/openshift/api v0.0.0-20240429104249-ac9356ba1784/go.mod h1:CxgbWAlvu2iQB0UmKTtRu1YfepRg1/vJ64n2DlIEVz4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= +k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE= +k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA= +k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/admin/main.go b/admin/main.go new file mode 100644 index 000000000..4c2ceb4f8 --- /dev/null +++ b/admin/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "context" + "log/slog" + "net" + "os" + "time" + + "github.com/Azure/ARO-HCP/admin/pkg/admin" +) + +func main() { + + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + + listener, _ := net.Listen("tcp", ":8446") + + // Initialize the Admin server + admin := admin.NewAdmin(logger, listener, "us-east") + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + time.Sleep(10 * time.Second) + cancel() + }() + + admin.Run(ctx, nil) +} diff --git a/admin/pkg/admin/admin.go b/admin/pkg/admin/admin.go new file mode 100644 index 000000000..bc570886e --- /dev/null +++ b/admin/pkg/admin/admin.go @@ -0,0 +1,63 @@ +package admin + +import ( + "context" + "fmt" + "log/slog" + "net" + "net/http" + "os" + "strings" + "sync/atomic" + + "github.com/Azure/ARO-HCP/internal/ocm" +) + +type Admin struct { + clusterServiceConfig ocm.ClusterServiceConfig + server http.Server + listener net.Listener + logger *slog.Logger + location string + done chan struct{} + ready atomic.Bool +} + +func NewAdmin(logger *slog.Logger, listener net.Listener, location string) *Admin { + a := &Admin{ + logger: logger, + listener: listener, + location: strings.ToLower(location), + done: make(chan struct{}), + } + + // Set up http.Server and routes via the separate routes() function + a.server = http.Server{ + Handler: a.adminRoutes(), // Separate function for setting up ServeMux + BaseContext: func(net.Listener) context.Context { + return context.WithValue(context.Background(), "logger", logger) + }, + } + + return a +} + +func (a *Admin) Run(ctx context.Context, stop <-chan struct{}) { + if stop != nil { + go func() { + <-stop + a.ready.Store(false) + _ = a.server.Shutdown(ctx) + }() + } + + a.logger.Info(fmt.Sprintf("listening on %s", a.listener.Addr().String())) + a.ready.Store(true) + + if err := a.server.Serve(a.listener); err != nil && err != http.ErrServerClosed { + a.logger.Error(err.Error()) + os.Exit(1) + } + + close(a.done) +} diff --git a/admin/pkg/admin/adminResourceList.go b/admin/pkg/admin/adminResourceList.go new file mode 100644 index 000000000..d3f88fe0a --- /dev/null +++ b/admin/pkg/admin/adminResourceList.go @@ -0,0 +1,156 @@ +package admin + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "strconv" + + "github.com/Azure/ARO-HCP/internal/api" + "github.com/Azure/ARO-HCP/internal/api/arm" + azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" +) + +func (a *Admin) AdminResourceList(writer http.ResponseWriter, request *http.Request) { + ctx := request.Context() + + versionedInterface, err := VersionFromContext(ctx) + if err != nil { + a.logger.Error(err.Error()) + arm.WriteInternalServerError(writer) + return + } + + var query string + subscriptionId := request.PathValue(PathSegmentSubscriptionID) + resourceGroupName := request.PathValue(PathSegmentResourceGroupName) + location := request.PathValue(PathSegmentLocation) + + switch { + case resourceGroupName != "": + query = fmt.Sprintf("azure.resource_group_name='%s'", resourceGroupName) + case location != "": + query = fmt.Sprintf("region.id='%s'", location) + case subscriptionId != "" && location == "" && resourceGroupName == "": + query = fmt.Sprintf("azure.subscription_id='%s'", subscriptionId) + } + + pageSize := 10 + pageNumber := 1 + + if pageStr := request.URL.Query().Get("page"); pageStr != "" { + pageNumber, _ = strconv.Atoi(pageStr) + } + if sizeStr := request.URL.Query().Get("size"); sizeStr != "" { + pageSize, _ = strconv.Atoi(sizeStr) + } + + // Create the request with initial parameters: + clustersRequest := a.clusterServiceConfig.Conn.ClustersMgmt().V2alpha1().Clusters().List().Search(query) + clustersRequest.Size(pageSize) + clustersRequest.Page(pageNumber) + + // Send the initial request: + clustersListResponse, err := clustersRequest.SendContext(ctx) + if err != nil { + a.logger.Error(err.Error()) + arm.WriteInternalServerError(writer) + return + } + + var hcpCluster *api.HCPOpenShiftCluster + var versionedHcpClusters []*api.VersionedHCPOpenShiftCluster + clusters := clustersListResponse.Items().Slice() + for _, cluster := range clusters { + // FIXME Temporary, until we have a real ResourceID to pass. + azcoreResourceID, err := azcorearm.ParseResourceID(fmt.Sprintf( + "/subscriptions/%s/resourceGroups/%s/providers/%s/%s", + subscriptionId, resourceGroupName, api.ResourceType, + cluster.Azure().ResourceName())) + if err != nil { + a.logger.Error(err.Error()) + arm.WriteInternalServerError(writer) + return + } + resourceID := &arm.ResourceID{ResourceID: *azcoreResourceID} + hcpCluster = ConvertCStoHCPOpenShiftCluster(resourceID, cluster) + versionedResource := versionedInterface.NewHCPOpenShiftCluster(hcpCluster) + versionedHcpClusters = append(versionedHcpClusters, &versionedResource) + } + + // Check if there are more pages to fetch and set NextLink if applicable: + var nextLink string + if clustersListResponse.Size() >= pageSize { + nextPage := pageNumber + 1 + nextLink = buildNextLink(request.URL.Path, request.URL.Query(), nextPage, pageSize) + } + + result := api.VersionedHCPOpenShiftClusterList{ + Value: versionedHcpClusters, + NextLink: &nextLink, + } + + resp, err := json.Marshal(result) + if err != nil { + a.logger.Error(err.Error()) + arm.WriteInternalServerError(writer) + return + } + + _, err = writer.Write(resp) + if err != nil { + a.logger.Error(err.Error()) + } +} + +func VersionFromContext(ctx context.Context) (api.Version, error) { + version, ok := ctx.Value(contextKeyVersion).(api.Version) + if !ok { + err := &ContextError{ + got: version, + } + return version, err + } + return version, nil +} + +func (c *ContextError) Error() string { + return fmt.Sprintf( + "error retrieving value from context, value obtained was '%v' and type obtained was '%T'", + c.got, + c.got) +} + +type contextKey int +type ContextError struct { + got any +} + +const ( + // Keys for request-scoped data in http.Request contexts + contextKeyOriginalPath contextKey = iota + contextKeyBody + contextKeyLogger + contextKeyVersion + contextKeyResourceID + contextKeyCorrelationData + contextKeySystemData + contextKeySubscription +) + +func buildNextLink(basePath string, queryParams url.Values, nextPage, pageSize int) string { + // Clone the existing query parameters + newParams := make(url.Values) + for key, values := range queryParams { + newParams[key] = values + } + + newParams.Set("page", strconv.Itoa(nextPage)) + newParams.Set("size", strconv.Itoa(pageSize)) + + // Construct the next link URL + nextLink := basePath + "?" + newParams.Encode() + return nextLink +} diff --git a/admin/pkg/admin/const.go b/admin/pkg/admin/const.go new file mode 100644 index 000000000..4d3e01e3e --- /dev/null +++ b/admin/pkg/admin/const.go @@ -0,0 +1,17 @@ +package admin + +const ( + ProgramName = "ARO HCP Admin" + + // APIVersionKey is the request parameter name for the API version. + APIVersionKey = "api-version" + + // Wildcard path segment names for request multiplexing, must be lowercase as we lowercase the request URL pattern when registering handlers + PathSegmentActionName = "actionname" + PathSegmentDeploymentName = "deploymentname" + PathSegmentLocation = "location" + PathSegmentNodePoolName = "nodepoolname" + PathSegmentResourceGroupName = "resourcegroupname" + PathSegmentResourceName = "resourcename" + PathSegmentSubscriptionID = "subscriptionid" +) diff --git a/admin/pkg/admin/ocm.go b/admin/pkg/admin/ocm.go new file mode 100644 index 000000000..7e151f997 --- /dev/null +++ b/admin/pkg/admin/ocm.go @@ -0,0 +1,82 @@ +package admin + +import ( + "github.com/Azure/ARO-HCP/internal/api" + "github.com/Azure/ARO-HCP/internal/api/arm" + cmv2alpha1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v2alpha1" + configv1 "github.com/openshift/api/config/v1" +) + +func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv2alpha1.Cluster) *api.HCPOpenShiftCluster { + hcpcluster := &api.HCPOpenShiftCluster{ + TrackedResource: arm.TrackedResource{ + Location: cluster.Region().ID(), + Resource: arm.Resource{ + ID: resourceID.String(), + Name: resourceID.Name, + Type: resourceID.ResourceType.String(), + }, + }, + Properties: api.HCPOpenShiftClusterProperties{ + // ProvisioningState: cluster.State(), // TODO: align with OCM on ProvisioningState + Spec: api.ClusterSpec{ + Version: api.VersionProfile{ + ID: cluster.Version().ID(), + ChannelGroup: cluster.Version().ChannelGroup(), + AvailableUpgrades: cluster.Version().AvailableUpgrades(), + }, + DNS: api.DNSProfile{ + BaseDomain: cluster.DNS().BaseDomain(), + BaseDomainPrefix: cluster.DomainPrefix(), + }, + Network: api.NetworkProfile{ + NetworkType: api.NetworkType(cluster.Network().Type()), + PodCIDR: cluster.Network().PodCIDR(), + ServiceCIDR: cluster.Network().ServiceCIDR(), + MachineCIDR: cluster.Network().MachineCIDR(), + HostPrefix: int32(cluster.Network().HostPrefix()), + }, + Console: api.ConsoleProfile{ + URL: cluster.Console().URL(), + }, + API: api.APIProfile{ + URL: cluster.API().URL(), + Visibility: convertListeningToVisibility(cluster.API().Listening()), + }, + FIPS: cluster.FIPS(), + EtcdEncryption: cluster.EtcdEncryption(), + DisableUserWorkloadMonitoring: cluster.DisableUserWorkloadMonitoring(), + Proxy: api.ProxyProfile{ + HTTPProxy: cluster.Proxy().HTTPProxy(), + HTTPSProxy: cluster.Proxy().HTTPSProxy(), + NoProxy: cluster.Proxy().NoProxy(), + TrustedCA: cluster.AdditionalTrustBundle(), + }, + Platform: api.PlatformProfile{ + ManagedResourceGroup: cluster.Azure().ManagedResourceGroupName(), + SubnetID: cluster.Azure().SubnetResourceID(), + OutboundType: api.OutboundTypeLoadBalancer, + NetworkSecurityGroupID: cluster.Azure().NetworkSecurityGroupResourceID(), + EtcdEncryptionSetID: "", + }, + IssuerURL: "", + ExternalAuth: api.ExternalAuthConfigProfile{ + Enabled: false, + ExternalAuths: []*configv1.OIDCProvider{}, + }, + }, + }, + } + + return hcpcluster +} + +func convertListeningToVisibility(listening cmv2alpha1.ListeningMethod) (visibility api.Visibility) { + switch listening { + case cmv2alpha1.ListeningMethodExternal: + visibility = api.VisibilityPublic + case cmv2alpha1.ListeningMethodInternal: + visibility = api.VisibilityPrivate + } + return +} diff --git a/admin/pkg/admin/routes.go b/admin/pkg/admin/routes.go new file mode 100644 index 000000000..eb648a4f1 --- /dev/null +++ b/admin/pkg/admin/routes.go @@ -0,0 +1,41 @@ +package admin + +import ( + "fmt" + "net/http" + "path" + "strings" + + "github.com/Azure/ARO-HCP/internal/api" +) + +const ( + WildcardActionName = "{" + PathSegmentActionName + "}" + WildcardDeploymentName = "{" + PathSegmentDeploymentName + "}" + WildcardLocation = "{" + PathSegmentLocation + "}" + WildcardNodePoolName = "{" + PathSegmentNodePoolName + "}" + WildcardResourceGroupName = "{" + PathSegmentResourceGroupName + "}" + WildcardResourceName = "{" + PathSegmentResourceName + "}" + WildcardSubscriptionID = "{" + PathSegmentSubscriptionID + "}" + + PatternSubscriptions = "subscriptions/" + WildcardSubscriptionID + PatternLocations = "locations/" + WildcardLocation + PatternProviders = "providers/" + api.ProviderNamespace + PatternClusters = api.ClusterResourceTypeName + "/" + WildcardResourceName + PatternNodePools = api.NodePoolResourceTypeName + "/" + WildcardNodePoolName + PatternDeployments = "deployments/" + WildcardDeploymentName + PatternResourceGroups = "resourcegroups/" + WildcardResourceGroupName +) + +func (a *Admin) adminRoutes() *http.ServeMux { + + adminMux := http.NewServeMux() + + adminMux.HandleFunc(MuxPattern(http.MethodGet, PatternSubscriptions, PatternProviders, api.ClusterResourceTypeName), a.AdminResourceList) + + return adminMux +} + +func MuxPattern(method string, segments ...string) string { + return fmt.Sprintf("%s /%s", method, strings.ToLower(path.Join(segments...))) +} From 27b0a7a06923e16d58c148df939f9b1a6489a74d Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Fri, 6 Sep 2024 10:29:36 -0400 Subject: [PATCH 02/11] refactor func to list clusters --- admin/main.go | 12 +++--- ...ourceList.go => adminClusterListfromCS.go} | 19 ++++---- admin/pkg/admin/routes.go | 43 +++++++------------ 3 files changed, 29 insertions(+), 45 deletions(-) rename admin/pkg/admin/{adminResourceList.go => adminClusterListfromCS.go} (84%) diff --git a/admin/main.go b/admin/main.go index 4c2ceb4f8..543ebd585 100644 --- a/admin/main.go +++ b/admin/main.go @@ -5,7 +5,6 @@ import ( "log/slog" "net" "os" - "time" "github.com/Azure/ARO-HCP/admin/pkg/admin" ) @@ -14,7 +13,11 @@ func main() { logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - listener, _ := net.Listen("tcp", ":8446") + listener, err := net.Listen("tcp", ":8443") + + if err != nil { + panic(err) + } // Initialize the Admin server admin := admin.NewAdmin(logger, listener, "us-east") @@ -22,10 +25,5 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - go func() { - time.Sleep(10 * time.Second) - cancel() - }() - admin.Run(ctx, nil) } diff --git a/admin/pkg/admin/adminResourceList.go b/admin/pkg/admin/adminClusterListfromCS.go similarity index 84% rename from admin/pkg/admin/adminResourceList.go rename to admin/pkg/admin/adminClusterListfromCS.go index d3f88fe0a..6117cf048 100644 --- a/admin/pkg/admin/adminResourceList.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -13,7 +13,7 @@ import ( azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" ) -func (a *Admin) AdminResourceList(writer http.ResponseWriter, request *http.Request) { +func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *http.Request) { ctx := request.Context() versionedInterface, err := VersionFromContext(ctx) @@ -24,17 +24,14 @@ func (a *Admin) AdminResourceList(writer http.ResponseWriter, request *http.Requ } var query string - subscriptionId := request.PathValue(PathSegmentSubscriptionID) - resourceGroupName := request.PathValue(PathSegmentResourceGroupName) - location := request.PathValue(PathSegmentLocation) + clusterID := request.URL.Query().Get("id") + clusterName := request.URL.Query().Get("name") switch { - case resourceGroupName != "": - query = fmt.Sprintf("azure.resource_group_name='%s'", resourceGroupName) - case location != "": - query = fmt.Sprintf("region.id='%s'", location) - case subscriptionId != "" && location == "" && resourceGroupName == "": - query = fmt.Sprintf("azure.subscription_id='%s'", subscriptionId) + case clusterName != "": + query = fmt.Sprintf("name='%s'", clusterName) + case clusterID != "": + query = fmt.Sprintf("id='%s'", clusterID) } pageSize := 10 @@ -67,7 +64,7 @@ func (a *Admin) AdminResourceList(writer http.ResponseWriter, request *http.Requ // FIXME Temporary, until we have a real ResourceID to pass. azcoreResourceID, err := azcorearm.ParseResourceID(fmt.Sprintf( "/subscriptions/%s/resourceGroups/%s/providers/%s/%s", - subscriptionId, resourceGroupName, api.ResourceType, + cluster.Azure().SubscriptionID(), cluster.Azure().ResourceGroupName(), api.ResourceType, cluster.Azure().ResourceName())) if err != nil { a.logger.Error(err.Error()) diff --git a/admin/pkg/admin/routes.go b/admin/pkg/admin/routes.go index eb648a4f1..9604c0d37 100644 --- a/admin/pkg/admin/routes.go +++ b/admin/pkg/admin/routes.go @@ -1,41 +1,30 @@ package admin import ( - "fmt" "net/http" - "path" "strings" - - "github.com/Azure/ARO-HCP/internal/api" -) - -const ( - WildcardActionName = "{" + PathSegmentActionName + "}" - WildcardDeploymentName = "{" + PathSegmentDeploymentName + "}" - WildcardLocation = "{" + PathSegmentLocation + "}" - WildcardNodePoolName = "{" + PathSegmentNodePoolName + "}" - WildcardResourceGroupName = "{" + PathSegmentResourceGroupName + "}" - WildcardResourceName = "{" + PathSegmentResourceName + "}" - WildcardSubscriptionID = "{" + PathSegmentSubscriptionID + "}" - - PatternSubscriptions = "subscriptions/" + WildcardSubscriptionID - PatternLocations = "locations/" + WildcardLocation - PatternProviders = "providers/" + api.ProviderNamespace - PatternClusters = api.ClusterResourceTypeName + "/" + WildcardResourceName - PatternNodePools = api.NodePoolResourceTypeName + "/" + WildcardNodePoolName - PatternDeployments = "deployments/" + WildcardDeploymentName - PatternResourceGroups = "resourcegroups/" + WildcardResourceGroupName ) func (a *Admin) adminRoutes() *http.ServeMux { adminMux := http.NewServeMux() - adminMux.HandleFunc(MuxPattern(http.MethodGet, PatternSubscriptions, PatternProviders, api.ClusterResourceTypeName), a.AdminResourceList) + adminMux.HandleFunc("/v1/ocm/clusters/id/", func(writer http.ResponseWriter, request *http.Request) { + // Extract ID from the URL + id := strings.TrimPrefix(request.URL.Path, "/v1/ocm/clusters/id/") + if id == "" { + http.Error(writer, "Cluster ID not provided", http.StatusBadRequest) + return + } + q := request.URL.Query() + q.Add("id", id) + request.URL.RawQuery = q.Encode() + a.AdminClustersListFromCS(writer, request) + }) + + adminMux.HandleFunc("/v1/ocm/clusters", func(writer http.ResponseWriter, request *http.Request) { + a.AdminClustersListFromCS(writer, request) + }) return adminMux } - -func MuxPattern(method string, segments ...string) string { - return fmt.Sprintf("%s /%s", method, strings.ToLower(path.Join(segments...))) -} From ed8e9a0d7a1cc35c5759014c91d0c4891121a749 Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Mon, 9 Sep 2024 13:26:12 -0400 Subject: [PATCH 03/11] add conn to ocm --- admin/cmd/cmd.go | 132 +++++++++++++++++++++++++++++++++++++++ admin/go.mod | 6 ++ admin/go.sum | 6 ++ admin/main.go | 23 ++----- admin/pkg/admin/admin.go | 4 ++ 5 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 admin/cmd/cmd.go diff --git a/admin/cmd/cmd.go b/admin/cmd/cmd.go new file mode 100644 index 000000000..81940d7c0 --- /dev/null +++ b/admin/cmd/cmd.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net" + "os" + "os/signal" + "runtime/debug" + "syscall" + + "github.com/Azure/ARO-HCP/admin/pkg/admin" + "github.com/Azure/ARO-HCP/internal/api" + "github.com/Azure/ARO-HCP/internal/ocm" + sdk "github.com/openshift-online/ocm-sdk-go" + "github.com/spf13/cobra" +) + +type AdminOpts struct { + clustersServiceURL string + clusterServiceProvisionShard string + clusterServiceNoopProvision bool + clusterServiceNoopDeprovision bool + insecure bool + + location string + port int +} + +func NewRootCmd() *cobra.Command { + opts := &AdminOpts{} + rootCmd := &cobra.Command{ + Use: "aro-hcp-admin", + Version: version(), + Args: cobra.NoArgs, + Short: "Serve the ARO HCP Admin", + Long: `Serve the ARO HCP Admin + + This command runs the ARO HCP Admin. + + # Run ARO HCP Admin locally to connect to a local Clusters Service at http://localhost:8000 + ./aro-hcp-admin --location ${LOCATION} --clusters-service-url "http://localhost:8000" +`, + RunE: func(cmd *cobra.Command, args []string) error { + return opts.Run() + }, + } + + rootCmd.Flags().StringVar(&opts.location, "location", os.Getenv("LOCATION"), "Azure location") + rootCmd.Flags().IntVar(&opts.port, "port", 8443, "port to listen on") + + rootCmd.Flags().StringVar(&opts.clustersServiceURL, "clusters-service-url", "https://api.openshift.com", "URL of the OCM API gateway.") + rootCmd.Flags().BoolVar(&opts.insecure, "insecure", false, "Skip validating TLS for clusters-service.") + rootCmd.Flags().StringVar(&opts.clusterServiceProvisionShard, "cluster-service-provision-shard", "", "Manually specify provision shard for all requests to cluster service") + rootCmd.Flags().BoolVar(&opts.clusterServiceNoopProvision, "cluster-service-noop-provision", false, "Skip cluster service provisioning steps for development purposes") + rootCmd.Flags().BoolVar(&opts.clusterServiceNoopDeprovision, "cluster-service-noop-deprovision", false, "Skip cluster service deprovisioning steps for development purposes") + + return rootCmd +} + +func (opts *AdminOpts) Run() error { + logger := DefaultLogger() + logger.Info(fmt.Sprintf("%s (%s) started", admin.ProgramName, version())) + + listener, err := net.Listen("tcp4", fmt.Sprintf(":%d", opts.port)) + if err != nil { + return err + } + + // Initialize Clusters Service Client + conn, err := sdk.NewUnauthenticatedConnectionBuilder(). + URL(opts.clustersServiceURL). + Insecure(opts.insecure). + Build() + if err != nil { + return err + } + + csCfg := ocm.ClusterServiceConfig{ + Conn: conn, + ProvisionerNoOpProvision: opts.clusterServiceNoopDeprovision, + ProvisionerNoOpDeprovision: opts.clusterServiceNoopDeprovision, + } + + if opts.clusterServiceProvisionShard != "" { + csCfg.ProvisionShardID = api.Ptr(opts.clusterServiceProvisionShard) + } + + if len(opts.location) == 0 { + return errors.New("location is required") + } + logger.Info(fmt.Sprintf("Application running in %s", opts.location)) + + adm := admin.NewAdmin(logger, listener, opts.location) + + stop := make(chan struct{}) + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM) + go adm.Run(context.Background(), stop) + + sig := <-signalChannel + logger.Info(fmt.Sprintf("caught %s signal", sig)) + close(stop) + + adm.Join() + logger.Info(fmt.Sprintf("%s (%s) stopped", admin.ProgramName, version())) + + return nil +} + +func version() string { + version := "unknown" + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + version = setting.Value + break + } + } + } + + return version +} + +func DefaultLogger() *slog.Logger { + handlerOptions := slog.HandlerOptions{} + handler := slog.NewJSONHandler(os.Stdout, &handlerOptions) + logger := slog.New(handler) + return logger +} diff --git a/admin/go.mod b/admin/go.mod index f6c1d02a8..183919c26 100644 --- a/admin/go.mod +++ b/admin/go.mod @@ -9,6 +9,11 @@ require ( github.com/openshift/api v0.0.0-20240429104249-ac9356ba1784 ) +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) + require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -37,6 +42,7 @@ require ( github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/spf13/cobra v1.8.1 golang.org/x/crypto v0.25.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect diff --git a/admin/go.sum b/admin/go.sum index 482aaa9b3..65bfa83ef 100644 --- a/admin/go.sum +++ b/admin/go.sum @@ -12,6 +12,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -53,6 +54,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/itchyny/gojq v0.12.7 h1:hYPTpeWfrJ1OT+2j6cvBScbhl0TkdwGM4bc66onUSOQ= github.com/itchyny/gojq v0.12.7/go.mod h1:ZdvNHVlzPgUf8pgjnuDTmGfHA/21KoutQUJ3An/xNuw= github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= @@ -117,8 +120,11 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/admin/main.go b/admin/main.go index 543ebd585..1f704e321 100644 --- a/admin/main.go +++ b/admin/main.go @@ -1,29 +1,18 @@ package main import ( - "context" - "log/slog" - "net" + "fmt" + "log" "os" + "github.com/Azure/ARO-HCP/admin/cmd" "github.com/Azure/ARO-HCP/admin/pkg/admin" ) func main() { - logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - - listener, err := net.Listen("tcp", ":8443") - - if err != nil { - panic(err) + if err := cmd.NewRootCmd().Execute(); err != nil { + log.Println(fmt.Errorf("%s error: %v", admin.ProgramName, err)) + os.Exit(1) } - - // Initialize the Admin server - admin := admin.NewAdmin(logger, listener, "us-east") - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - admin.Run(ctx, nil) } diff --git a/admin/pkg/admin/admin.go b/admin/pkg/admin/admin.go index bc570886e..2682f6795 100644 --- a/admin/pkg/admin/admin.go +++ b/admin/pkg/admin/admin.go @@ -61,3 +61,7 @@ func (a *Admin) Run(ctx context.Context, stop <-chan struct{}) { close(a.done) } + +func (a *Admin) Join() { + <-a.done +} From 18d33a13f75bacde0995fd41ed31c26b4d954250 Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Wed, 11 Sep 2024 12:10:01 -0400 Subject: [PATCH 04/11] fix context --- admin/main.go | 2 +- admin/pkg/admin/adminClusterListfromCS.go | 19 +++++++++++++++++++ admin/pkg/admin/const.go | 9 --------- admin/pkg/admin/routes.go | 8 ++++---- go.work | 5 ++--- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/admin/main.go b/admin/main.go index 1f704e321..890bbae6c 100644 --- a/admin/main.go +++ b/admin/main.go @@ -1,4 +1,4 @@ -package main +package pkg import ( "fmt" diff --git a/admin/pkg/admin/adminClusterListfromCS.go b/admin/pkg/admin/adminClusterListfromCS.go index 6117cf048..542e92ce9 100644 --- a/admin/pkg/admin/adminClusterListfromCS.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -113,6 +113,10 @@ func VersionFromContext(ctx context.Context) (api.Version, error) { return version, nil } +func ContextWithVersion(ctx context.Context, version api.Version) context.Context { + return context.WithValue(ctx, contextKeyVersion, version) +} + func (c *ContextError) Error() string { return fmt.Sprintf( "error retrieving value from context, value obtained was '%v' and type obtained was '%T'", @@ -151,3 +155,18 @@ func buildNextLink(basePath string, queryParams url.Values, nextPage, pageSize i nextLink := basePath + "?" + newParams.Encode() return nextLink } + +func (a *Admin) HandleVersionedAPI(next http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, r *http.Request) { + + var apiRegistry = map[string]api.Version{} + apiVersion := r.URL.Query().Get(APIVersionKey) + version, exists := apiRegistry[apiVersion] + if !exists { + http.Error(writer, "Unsupported or missing API version", http.StatusBadRequest) + return + } + ctx := ContextWithVersion(r.Context(), version) + next.ServeHTTP(writer, r.WithContext(ctx)) + } +} diff --git a/admin/pkg/admin/const.go b/admin/pkg/admin/const.go index 4d3e01e3e..db74d114b 100644 --- a/admin/pkg/admin/const.go +++ b/admin/pkg/admin/const.go @@ -5,13 +5,4 @@ const ( // APIVersionKey is the request parameter name for the API version. APIVersionKey = "api-version" - - // Wildcard path segment names for request multiplexing, must be lowercase as we lowercase the request URL pattern when registering handlers - PathSegmentActionName = "actionname" - PathSegmentDeploymentName = "deploymentname" - PathSegmentLocation = "location" - PathSegmentNodePoolName = "nodepoolname" - PathSegmentResourceGroupName = "resourcegroupname" - PathSegmentResourceName = "resourcename" - PathSegmentSubscriptionID = "subscriptionid" ) diff --git a/admin/pkg/admin/routes.go b/admin/pkg/admin/routes.go index 9604c0d37..23217a21b 100644 --- a/admin/pkg/admin/routes.go +++ b/admin/pkg/admin/routes.go @@ -9,7 +9,7 @@ func (a *Admin) adminRoutes() *http.ServeMux { adminMux := http.NewServeMux() - adminMux.HandleFunc("/v1/ocm/clusters/id/", func(writer http.ResponseWriter, request *http.Request) { + adminMux.HandleFunc("/v1/ocm/clusters/id/", a.HandleVersionedAPI(func(writer http.ResponseWriter, request *http.Request) { // Extract ID from the URL id := strings.TrimPrefix(request.URL.Path, "/v1/ocm/clusters/id/") if id == "" { @@ -20,11 +20,11 @@ func (a *Admin) adminRoutes() *http.ServeMux { q.Add("id", id) request.URL.RawQuery = q.Encode() a.AdminClustersListFromCS(writer, request) - }) + })) - adminMux.HandleFunc("/v1/ocm/clusters", func(writer http.ResponseWriter, request *http.Request) { + adminMux.HandleFunc("/v1/ocm/clusters", a.HandleVersionedAPI(func(writer http.ResponseWriter, request *http.Request) { a.AdminClustersListFromCS(writer, request) - }) + })) return adminMux } diff --git a/go.work b/go.work index 6cd76128d..95787983f 100644 --- a/go.work +++ b/go.work @@ -1,8 +1,7 @@ -go 1.22.0 - -toolchain go1.22.2 +go 1.22.2 use ( + ./admin ./frontend ./internal ./tooling/image-sync From e8e4deafde38f83cedfc5fc21693669d0a70e9ef Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Wed, 11 Sep 2024 13:28:58 -0400 Subject: [PATCH 05/11] fix pkg --- admin/main.go | 2 +- admin/pkg/admin/adminClusterListfromCS.go | 84 ++++------------------- admin/pkg/admin/routes.go | 8 +-- 3 files changed, 17 insertions(+), 77 deletions(-) diff --git a/admin/main.go b/admin/main.go index 890bbae6c..1f704e321 100644 --- a/admin/main.go +++ b/admin/main.go @@ -1,4 +1,4 @@ -package pkg +package main import ( "fmt" diff --git a/admin/pkg/admin/adminClusterListfromCS.go b/admin/pkg/admin/adminClusterListfromCS.go index 542e92ce9..35b8f8046 100644 --- a/admin/pkg/admin/adminClusterListfromCS.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -1,7 +1,6 @@ package admin import ( - "context" "encoding/json" "fmt" "net/http" @@ -16,23 +15,19 @@ import ( func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *http.Request) { ctx := request.Context() - versionedInterface, err := VersionFromContext(ctx) - if err != nil { - a.logger.Error(err.Error()) - arm.WriteInternalServerError(writer) - return - } + apiVersion := request.URL.Query().Get(APIVersionKey) + versionedInterface, _ := api.Lookup(apiVersion) - var query string - clusterID := request.URL.Query().Get("id") - clusterName := request.URL.Query().Get("name") + /* var query string + clusterID := request.URL.Query().Get("id") + clusterName := request.URL.Query().Get("name") - switch { - case clusterName != "": - query = fmt.Sprintf("name='%s'", clusterName) - case clusterID != "": - query = fmt.Sprintf("id='%s'", clusterID) - } + switch { + case clusterName != "": + query = fmt.Sprintf("name='%s'", clusterName) + case clusterID != "": + query = fmt.Sprintf("id='%s'", clusterID) + } */ pageSize := 10 pageNumber := 1 @@ -44,8 +39,7 @@ func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *htt pageSize, _ = strconv.Atoi(sizeStr) } - // Create the request with initial parameters: - clustersRequest := a.clusterServiceConfig.Conn.ClustersMgmt().V2alpha1().Clusters().List().Search(query) + clustersRequest := a.clusterServiceConfig.Conn.ClustersMgmt().V2alpha1().Clusters().List() clustersRequest.Size(pageSize) clustersRequest.Page(pageNumber) @@ -102,45 +96,6 @@ func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *htt } } -func VersionFromContext(ctx context.Context) (api.Version, error) { - version, ok := ctx.Value(contextKeyVersion).(api.Version) - if !ok { - err := &ContextError{ - got: version, - } - return version, err - } - return version, nil -} - -func ContextWithVersion(ctx context.Context, version api.Version) context.Context { - return context.WithValue(ctx, contextKeyVersion, version) -} - -func (c *ContextError) Error() string { - return fmt.Sprintf( - "error retrieving value from context, value obtained was '%v' and type obtained was '%T'", - c.got, - c.got) -} - -type contextKey int -type ContextError struct { - got any -} - -const ( - // Keys for request-scoped data in http.Request contexts - contextKeyOriginalPath contextKey = iota - contextKeyBody - contextKeyLogger - contextKeyVersion - contextKeyResourceID - contextKeyCorrelationData - contextKeySystemData - contextKeySubscription -) - func buildNextLink(basePath string, queryParams url.Values, nextPage, pageSize int) string { // Clone the existing query parameters newParams := make(url.Values) @@ -155,18 +110,3 @@ func buildNextLink(basePath string, queryParams url.Values, nextPage, pageSize i nextLink := basePath + "?" + newParams.Encode() return nextLink } - -func (a *Admin) HandleVersionedAPI(next http.HandlerFunc) http.HandlerFunc { - return func(writer http.ResponseWriter, r *http.Request) { - - var apiRegistry = map[string]api.Version{} - apiVersion := r.URL.Query().Get(APIVersionKey) - version, exists := apiRegistry[apiVersion] - if !exists { - http.Error(writer, "Unsupported or missing API version", http.StatusBadRequest) - return - } - ctx := ContextWithVersion(r.Context(), version) - next.ServeHTTP(writer, r.WithContext(ctx)) - } -} diff --git a/admin/pkg/admin/routes.go b/admin/pkg/admin/routes.go index 23217a21b..9604c0d37 100644 --- a/admin/pkg/admin/routes.go +++ b/admin/pkg/admin/routes.go @@ -9,7 +9,7 @@ func (a *Admin) adminRoutes() *http.ServeMux { adminMux := http.NewServeMux() - adminMux.HandleFunc("/v1/ocm/clusters/id/", a.HandleVersionedAPI(func(writer http.ResponseWriter, request *http.Request) { + adminMux.HandleFunc("/v1/ocm/clusters/id/", func(writer http.ResponseWriter, request *http.Request) { // Extract ID from the URL id := strings.TrimPrefix(request.URL.Path, "/v1/ocm/clusters/id/") if id == "" { @@ -20,11 +20,11 @@ func (a *Admin) adminRoutes() *http.ServeMux { q.Add("id", id) request.URL.RawQuery = q.Encode() a.AdminClustersListFromCS(writer, request) - })) + }) - adminMux.HandleFunc("/v1/ocm/clusters", a.HandleVersionedAPI(func(writer http.ResponseWriter, request *http.Request) { + adminMux.HandleFunc("/v1/ocm/clusters", func(writer http.ResponseWriter, request *http.Request) { a.AdminClustersListFromCS(writer, request) - })) + }) return adminMux } From 485484e063cc80c93dd87eb4cae08a6d2e2ed903 Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Wed, 11 Sep 2024 16:10:41 -0400 Subject: [PATCH 06/11] fix ctx --- admin/pkg/admin/admin.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/admin/pkg/admin/admin.go b/admin/pkg/admin/admin.go index 2682f6795..a9027e392 100644 --- a/admin/pkg/admin/admin.go +++ b/admin/pkg/admin/admin.go @@ -35,7 +35,7 @@ func NewAdmin(logger *slog.Logger, listener net.Listener, location string) *Admi a.server = http.Server{ Handler: a.adminRoutes(), // Separate function for setting up ServeMux BaseContext: func(net.Listener) context.Context { - return context.WithValue(context.Background(), "logger", logger) + return ContextWithLogger(context.Background(), logger) }, } @@ -65,3 +65,15 @@ func (a *Admin) Run(ctx context.Context, stop <-chan struct{}) { func (a *Admin) Join() { <-a.done } + +func ContextWithLogger(ctx context.Context, logger *slog.Logger) context.Context { + return context.WithValue(ctx, contextKeyLogger, logger) +} + +type contextKey int + +const ( + // Keys for request-scoped data in http.Request contexts + contextKeyOriginalPath contextKey = iota + contextKeyLogger +) From 932307c70fa9d1a573e7cdc95deb8c6640903cfe Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Thu, 12 Sep 2024 09:45:53 -0400 Subject: [PATCH 07/11] fix linting error --- admin/cmd/cmd.go | 5 +++-- admin/pkg/admin/adminClusterListfromCS.go | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/admin/cmd/cmd.go b/admin/cmd/cmd.go index 81940d7c0..0da791e42 100644 --- a/admin/cmd/cmd.go +++ b/admin/cmd/cmd.go @@ -11,11 +11,12 @@ import ( "runtime/debug" "syscall" + sdk "github.com/openshift-online/ocm-sdk-go" + "github.com/spf13/cobra" + "github.com/Azure/ARO-HCP/admin/pkg/admin" "github.com/Azure/ARO-HCP/internal/api" "github.com/Azure/ARO-HCP/internal/ocm" - sdk "github.com/openshift-online/ocm-sdk-go" - "github.com/spf13/cobra" ) type AdminOpts struct { diff --git a/admin/pkg/admin/adminClusterListfromCS.go b/admin/pkg/admin/adminClusterListfromCS.go index 35b8f8046..b3b5ba39c 100644 --- a/admin/pkg/admin/adminClusterListfromCS.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -7,9 +7,10 @@ import ( "net/url" "strconv" + azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" + "github.com/Azure/ARO-HCP/internal/api" "github.com/Azure/ARO-HCP/internal/api/arm" - azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" ) func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *http.Request) { From 64f44d2e3702152f03c08f75dc0d2fa1ffbd68dd Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Thu, 12 Sep 2024 10:02:43 -0400 Subject: [PATCH 08/11] fix lint --- admin/pkg/admin/ocm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/admin/pkg/admin/ocm.go b/admin/pkg/admin/ocm.go index 7e151f997..be566f929 100644 --- a/admin/pkg/admin/ocm.go +++ b/admin/pkg/admin/ocm.go @@ -1,10 +1,11 @@ package admin import ( - "github.com/Azure/ARO-HCP/internal/api" - "github.com/Azure/ARO-HCP/internal/api/arm" cmv2alpha1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v2alpha1" configv1 "github.com/openshift/api/config/v1" + + "github.com/Azure/ARO-HCP/internal/api" + "github.com/Azure/ARO-HCP/internal/api/arm" ) func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv2alpha1.Cluster) *api.HCPOpenShiftCluster { From d2f6530f758261e50c28e63027c74be2e8ac5e5b Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Thu, 12 Sep 2024 11:55:31 -0400 Subject: [PATCH 09/11] fix ocm api --- admin/cmd/cmd.go | 2 +- admin/pkg/admin/admin.go | 11 ++++++----- admin/pkg/admin/adminClusterListfromCS.go | 2 +- admin/pkg/admin/ocm.go | 10 +++++----- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/admin/cmd/cmd.go b/admin/cmd/cmd.go index 0da791e42..2376b7f6c 100644 --- a/admin/cmd/cmd.go +++ b/admin/cmd/cmd.go @@ -94,7 +94,7 @@ func (opts *AdminOpts) Run() error { } logger.Info(fmt.Sprintf("Application running in %s", opts.location)) - adm := admin.NewAdmin(logger, listener, opts.location) + adm := admin.NewAdmin(logger, listener, opts.location, csCfg) stop := make(chan struct{}) signalChannel := make(chan os.Signal, 1) diff --git a/admin/pkg/admin/admin.go b/admin/pkg/admin/admin.go index a9027e392..230bdb1a0 100644 --- a/admin/pkg/admin/admin.go +++ b/admin/pkg/admin/admin.go @@ -23,12 +23,13 @@ type Admin struct { ready atomic.Bool } -func NewAdmin(logger *slog.Logger, listener net.Listener, location string) *Admin { +func NewAdmin(logger *slog.Logger, listener net.Listener, location string, csCfg ocm.ClusterServiceConfig) *Admin { a := &Admin{ - logger: logger, - listener: listener, - location: strings.ToLower(location), - done: make(chan struct{}), + clusterServiceConfig: csCfg, + logger: logger, + listener: listener, + location: strings.ToLower(location), + done: make(chan struct{}), } // Set up http.Server and routes via the separate routes() function diff --git a/admin/pkg/admin/adminClusterListfromCS.go b/admin/pkg/admin/adminClusterListfromCS.go index b3b5ba39c..9647d3a8a 100644 --- a/admin/pkg/admin/adminClusterListfromCS.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -40,7 +40,7 @@ func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *htt pageSize, _ = strconv.Atoi(sizeStr) } - clustersRequest := a.clusterServiceConfig.Conn.ClustersMgmt().V2alpha1().Clusters().List() + clustersRequest := a.clusterServiceConfig.Conn.ClustersMgmt().V1().Clusters().List() clustersRequest.Size(pageSize) clustersRequest.Page(pageNumber) diff --git a/admin/pkg/admin/ocm.go b/admin/pkg/admin/ocm.go index be566f929..def4343dd 100644 --- a/admin/pkg/admin/ocm.go +++ b/admin/pkg/admin/ocm.go @@ -1,14 +1,14 @@ package admin import ( - cmv2alpha1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v2alpha1" + cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" configv1 "github.com/openshift/api/config/v1" "github.com/Azure/ARO-HCP/internal/api" "github.com/Azure/ARO-HCP/internal/api/arm" ) -func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv2alpha1.Cluster) *api.HCPOpenShiftCluster { +func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv1.Cluster) *api.HCPOpenShiftCluster { hcpcluster := &api.HCPOpenShiftCluster{ TrackedResource: arm.TrackedResource{ Location: cluster.Region().ID(), @@ -72,11 +72,11 @@ func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv2alp return hcpcluster } -func convertListeningToVisibility(listening cmv2alpha1.ListeningMethod) (visibility api.Visibility) { +func convertListeningToVisibility(listening cmv1.ListeningMethod) (visibility api.Visibility) { switch listening { - case cmv2alpha1.ListeningMethodExternal: + case cmv1.ListeningMethodExternal: visibility = api.VisibilityPublic - case cmv2alpha1.ListeningMethodInternal: + case cmv1.ListeningMethodInternal: visibility = api.VisibilityPrivate } return From cd8b9d8d63f0834d92ffc394d3b0d8c14065affc Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Thu, 12 Sep 2024 11:58:25 -0400 Subject: [PATCH 10/11] rm comment --- admin/pkg/admin/adminClusterListfromCS.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/admin/pkg/admin/adminClusterListfromCS.go b/admin/pkg/admin/adminClusterListfromCS.go index 9647d3a8a..201341078 100644 --- a/admin/pkg/admin/adminClusterListfromCS.go +++ b/admin/pkg/admin/adminClusterListfromCS.go @@ -19,17 +19,6 @@ func (a *Admin) AdminClustersListFromCS(writer http.ResponseWriter, request *htt apiVersion := request.URL.Query().Get(APIVersionKey) versionedInterface, _ := api.Lookup(apiVersion) - /* var query string - clusterID := request.URL.Query().Get("id") - clusterName := request.URL.Query().Get("name") - - switch { - case clusterName != "": - query = fmt.Sprintf("name='%s'", clusterName) - case clusterID != "": - query = fmt.Sprintf("id='%s'", clusterID) - } */ - pageSize := 10 pageNumber := 1 From f6b52ab80d4ab3fcc39517bb0bd0d7f46a4473d7 Mon Sep 17 00:00:00 2001 From: katherinelc321 Date: Fri, 13 Sep 2024 12:42:59 -0400 Subject: [PATCH 11/11] add api init file --- admin/apiversions.go | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 admin/apiversions.go diff --git a/admin/apiversions.go b/admin/apiversions.go new file mode 100644 index 000000000..ff58862fd --- /dev/null +++ b/admin/apiversions.go @@ -0,0 +1,10 @@ +package main + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +// This will invoke the init() function in each +// API version package so it can register itself. +import ( + _ "github.com/Azure/ARO-HCP/internal/api/v20240610preview" +)