diff --git a/.github/workflows/component-linter.yml b/.github/workflows/component-linter.yml index 72cfd0440..bc5deca94 100644 --- a/.github/workflows/component-linter.yml +++ b/.github/workflows/component-linter.yml @@ -16,6 +16,7 @@ jobs: directory: - app - cleaner + - filebrowser - mlflow - project-operator - repo-cloner diff --git a/.github/workflows/releases-create.yml b/.github/workflows/releases-create.yml index 4404551c5..2a3ce4a10 100644 --- a/.github/workflows/releases-create.yml +++ b/.github/workflows/releases-create.yml @@ -5,7 +5,7 @@ name: "[Releases] Create" env: - COMPONENTS: "app,cleaner,mlflow,project-operator,repo-cloner,user-tools-operator" + COMPONENTS: "app,cleaner,filebrowser,mlflow,project-operator,repo-cloner,user-tools-operator" on: workflow_dispatch: @@ -18,6 +18,7 @@ on: - all - kdl-app - cleaner + - filebrowser - mlflow - project-operator - repo-cloner diff --git a/app/api/.env.dev b/app/api/.env.dev deleted file mode 100644 index 6f46ef592..000000000 --- a/app/api/.env.dev +++ /dev/null @@ -1,23 +0,0 @@ -USER_TOOLS_VSCODE_RUNTIME_IMG_PULLPOLICY=IfNotPresent -USER_TOOLS_VSCODE_RUNTIME_IMG_REPO=localhost:32000/konstellation/jupyter-flavors-kai-python-tf -USER_TOOLS_VSCODE_RUNTIME_IMG_TAG=latest -KDL_ENV=dev -KDL_SERVER_MONGODB_URI=mongodb://admin:123456@localhost:27017/admin -MINIO_ENDPOINT=localhost -POD_NAMESPACE=kdl -REPO_CLONER_IMG_PULLPOLICY=IfNotPresent -REPO_CLONER_IMG_REPO=localhost:32000/konstellation/repo-cloner -REPO_CLONER_IMG_TAG=latest -BASE_DOMAIN_NAME=toolkit.local -SHARED_VOLUME="" -USER_TOOLS_OAUTH2_PROXY_IMG_PULLPOLICY=IfNotPresent -USER_TOOLS_OAUTH2_PROXY_IMG_REPO=quay.io/oauth2-proxy/oauth2-proxy -USER_TOOLS_OAUTH2_PROXY_IMG_TAG=v7.7.1-amd64 -USER_TOOLS_STORAGE_CLASSNAME=microk8s-hostpath -USER_TOOLS_STORAGE_SIZE=10Gi -VSCODE_IMG_PULLPOLICY=IfNotPresent -USER_TOOLS_VSCODE_ENABLED=true -VSCODE_IMG_REPO=localhost:32000/konstellation/vscode -VSCODE_IMG_TAG=latest -USER_TOOLS_KUBECONFIG_DOWNLOAD_ENABLED=true -USER_TOOLS_KUBECONFIG_EXTERNAL_SERVER_URL=https://192.168.0.21:16443 diff --git a/app/api/README.md b/app/api/README.md index 2ea5d66ce..0996ec2b0 100644 --- a/app/api/README.md +++ b/app/api/README.md @@ -38,16 +38,19 @@ docker build \ #### KDL server -| Environment variable | Description | Default value | -|--------------------------------|---------------------------------------------|----------------| -| `BASE_DOMAIN_NAME` | Base domain name for the KDL server | `kdl.local` | -| `KDL_SERVER_MONGODB_NAME` | MongoDB Database name for the KDL server | | -| `KDL_SERVER_MONGODB_URI` | MongoDB URI for the KDL server | | -| `KDL_SERVER_PORT` | Port for the KDL API | `8080` | -| `KDL_SERVER_STATIC_FILES_PATH` | Path for the static files of the KDL server | | -| `POD_NAMESPACE` | Namespace for the KDL server | | -| `SHARED_VOLUME` | Shared volume for the KDL server | | -| `TLS_ENABLED` | Enable TLS for the KDL server | `true` | +| Environment variable | Description | Default value | +|----------------------------------|-----------------------------------------------|------------------------------------------------------------------------| +| `RELEASE_NAME` | Release name for the KDL server | `kdl-local` | +| `KDL_SERVER_MONGODB_NAME` | MongoDB Database name for the KDL server | | +| `KDL_SERVER_MONGODB_URI` | MongoDB URI for the KDL server | | +| `KDL_SERVER_PORT` | Port for the KDL API | `8080` | +| `KDL_SERVER_STATIC_FILES_PATH` | Path for the static files of the KDL server | | +| `POD_NAMESPACE` | Namespace for the KDL server | | +| `PROJECT_FILEBROWSER_URL` | URL for the File Browser service | `http://kdlapp.kdl.local/filebrowser/PROJECT_ID/` | +| `PROJECT_MLFLOW_URL` | URL for the MLflow service | `http://kdlapp.kdl.local/mlflow/PROJECT_ID/` | +| `USER_TOOLS_VSCODE_URL` | URL for the VScode service | `http://USERNAME-code.kdl.local/?folder=/home/coder/repos/REPO_FOLDER` | +| `KUBECONFIG_DOWNLOAD_ENABLED` | Enable kubeconfig download for the User Tools | `false` | +| `KUBECONFIG_EXTERNAL_SERVER_URL` | URL for the kubeconfig download service | | #### KnowledgeGalaxy @@ -64,79 +67,7 @@ docker build \ | `MINIO_ENDPOINT` | URL for the Minio service | `http://minio:9000` | | `MINIO_SECRET_KEY` | Secret key for the Minio service | | -### Filebrowser - -| Environment variable | Description | Default value | -|--------------------------------------|----------------------------------------------------|---------------------------------------------------| -| `PROJECT_FILEBROWSER_AFFINITY` | Encoded affinity for the File Browser service | `{}` | -| `PROJECT_FILEBROWSER_IMG_PULLPOLICY` | Pull policy for the File Browser image | `IfNotPresent` | -| `PROJECT_FILEBROWSER_IMG_REPO` | Repository for the File Browser image | `filebrowser/filebrowser` | -| `PROJECT_FILEBROWSER_IMG_TAG` | Tag for the File Browser image | `v2` | -| `PROJECT_FILEBROWSER_NODESELECTOR` | Encoded node selector for the File Browser service | `{}` | -| `PROJECT_FILEBROWSER_TOLERATIONS` | Encoded tolerations for the File Browser service | `[]` | -| `PROJECT_FILEBROWSER_URL` | URL for the File Browser service | `http://kdlapp.kdl.local/filebrowser/PROJECT_ID/` | - -### MLflow - -| Environment variable | Description | Default value | -|----------------------------------------------|----------------------------------------------------|----------------------------------------------| -| `PROJECT_MLFLOW_AFFINITY` | Encoded affinity for the MLflow service | `{}` | -| `PROJECT_MLFLOW_ENCODED_INGRESS_ANNOTATIONS` | Encoded ingress annotations for the MLflow service | `{}` | -| `PROJECT_MLFLOW_IMG_PULLPOLICY` | Pull policy for the MLflow image | `IfNotPresent` | -| `PROJECT_MLFLOW_IMG_REPO` | Repository for the MLflow image | `konstellation/kdl-mlflow` | -| `PROJECT_MLFLOW_IMG_TAG` | Tag for the MLflow image | `v0.13.5` | -| `PROJECT_MLFLOW_INGRESS_CLASS_NAME` | Ingress class name for the MLflow service | `nginx` | -| `PROJECT_MLFLOW_INGRESS_TLS_SECRET_NAME` | TLS secret name for the MLflow service | | -| `PROJECT_MLFLOW_NODESELECTOR` | Encoded node selector for the MLflow service | `{}` | -| `PROJECT_MLFLOW_STORAGE_CLASS_NAME` | Storage class name for the MLflow service | `standard` | -| `PROJECT_MLFLOW_STORAGE_SIZE` | Storage size for the MLflow service | `1Gi` | -| `PROJECT_MLFLOW_TOLERATIONS` | Encoded tolerations for the MLflow service | `[]` | -| `PROJECT_MLFLOW_URL` | URL for the MLflow service | `http://kdlapp.kdl.local/mlflow/PROJECT_ID/` | - -### oauth2-proxy - -| Environment variable | Description | Default value | -|-------------------------------|----------------------------------------|-------------------------------------| -| `OAUTH2_PROXY_IMG_PULLPOLICY` | Pull policy for the oauth2-proxy image | `IfNotPresent` | -| `OAUTH2_PROXY_IMG_REPO` | Repository for the oauth2-proxy image | `quay.io/oauth2-proxy/oauth2-proxy` | -| `OAUTH2_PROXY_IMG_TAG` | Tag for the oauth2-proxy image | `v7.0.1-amd64` | - -### VScode - -| Environment variable | Description | Default value | -|-------------------------|----------------------------------|----------------------------| -| `VSCODE_IMG_PULLPOLICY` | Pull policy for the VScode image | `IfNotPresent` | -| `VSCODE_IMG_REPO` | Repository for the VScode image | `konstellation/kdl-vscode` | -| `VSCODE_IMG_TAG` | Tag for the VScode image | `v0.15.0` | - -### repo-cloner - -| Environment variable | Description | Default value | -|------------------------------|---------------------------------------|---------------------------------| -| `REPO_CLONER_IMG_PULLPOLICY` | Pull policy for the repo-cloner image | `IfNotPresent` | -| `REPO_CLONER_IMG_REPO` | Repository for the repo-cloner image | `konstellation/kdl-repo-cloner` | -| `REPO_CLONER_IMG_TAG` | Tag for the repo-cloner image | `0.18.0` | - -### user-tools-operator - -| Environment variable | Description | Default value | -|---------------------------------------------|--------------------------------------------------------|------------------------------------------------------------------------| -| `USER_TOOLS_ENCODED_INGRESS_ANNOTATIONS` | Encoded ingress annotations for the User Tools service | `{}` | -| `USER_TOOLS_INGRESS_CLASS_NAME` | Ingress class name for the User Tools service | `nginx` | -| `USER_TOOLS_KUBECONFIG_DOWNLOAD_ENABLED` | Enable kubeconfig download for the User Tools service | `false` | -| `USER_TOOLS_KUBECONFIG_EXTERNAL_SERVER_URL` | URL for the kubeconfig download service | | -| `USER_TOOLS_OAUTH2_PROXY_IMG_PULLPOLICY` | Pull policy for the VScode image | `IfNotPresent` | -| `USER_TOOLS_OAUTH2_PROXY_IMG_REPO` | Repository for the oauth2-proxy image | `quay.io/oauth2-proxy/oauth2-proxy` | -| `USER_TOOLS_OAUTH2_PROXY_IMG_TAG` | Tag for the oauth2-proxy image | `v7.0.1-amd64` | -| `USER_TOOLS_STORAGE_CLASSNAME` | Storage class name for the User Tools service | `standard` | -| `USER_TOOLS_STORAGE_SIZE` | Storage size for the User Tools service | `10Gi` | -| `USER_TOOLS_TLS_SECRET_NAME` | TLS secret name for the User Tools service | | -| `USER_TOOLS_VSCODE_RUNTIME_IMG_PULLPOLICY` | Pull policy for the VScode Runtime image | `IfNotPresent` | -| `USER_TOOLS_VSCODE_RUNTIME_IMG_REPO` | Repository for the VScode Runtime image | `konstellation/kdl-py` | -| `USER_TOOLS_VSCODE_RUNTIME_IMG_TAG` | Tag for the VScode Runtime image | `3.9` | -| `USER_TOOLS_VSCODE_URL` | URL for the VScode service | `http://USERNAME-code.kdl.local/?folder=/home/coder/repos/REPO_FOLDER` | - -### Labels +#### Labels | Environment variable | Default value | Description | |-------------------------------|---------------|------------------------------------------------------------------------------| diff --git a/app/api/go.mod b/app/api/go.mod index a2ee8d735..737a9c01b 100644 --- a/app/api/go.mod +++ b/app/api/go.mod @@ -4,7 +4,7 @@ go 1.23.2 require ( bou.ke/monkey v1.0.2 - github.com/99designs/gqlgen v0.17.60 + github.com/99designs/gqlgen v0.17.61 github.com/go-co-op/gocron v1.37.0 github.com/go-logr/logr v1.4.2 github.com/go-logr/zapr v1.3.0 @@ -18,7 +18,7 @@ require ( github.com/vektah/gqlparser/v2 v2.5.20 go.mongodb.org/mongo-driver v1.17.1 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.30.0 + golang.org/x/crypto v0.31.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools/v3 v3.5.1 k8s.io/api v0.32.0 @@ -109,7 +109,7 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.30.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/app/api/go.sum b/app/api/go.sum index 8ba11e54e..6a70bd9bf 100644 --- a/app/api/go.sum +++ b/app/api/go.sum @@ -2,8 +2,8 @@ bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/99designs/gqlgen v0.17.60 h1:xxl7kQDCNw79itzWQtCUSXgkovCyq9r+ogSXfZpKPYM= -github.com/99designs/gqlgen v0.17.60/go.mod h1:vQJzWXyGya2TYL7cig1G4OaCQzyck031MgYBlUwaI9I= +github.com/99designs/gqlgen v0.17.61 h1:vE7xLRC066n9wehgjeplILOWtwz75zbzcV2/Iv9i3pw= +github.com/99designs/gqlgen v0.17.61/go.mod h1:rFU1T3lhv/tPeAlww/DJ4ol2YxT/pPpue+xxPbkd3r4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -277,8 +277,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -290,8 +290,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/app/api/infrastructure/config/config.go b/app/api/infrastructure/config/config.go index e4dd3791f..c6c21b0bb 100644 --- a/app/api/infrastructure/config/config.go +++ b/app/api/infrastructure/config/config.go @@ -15,22 +15,13 @@ type KubernetesConfig struct { // Config holds the configuration values of the application. type Config struct { - LogLevel string `yaml:"logLevel" envconfig:"KDL_SERVER_LOG_LEVEL"` // currently unused - Port string `yaml:"port" envconfig:"KDL_SERVER_PORT"` - StaticFilesPath string `yaml:"staticFilesPath" envconfig:"KDL_SERVER_STATIC_FILES_PATH"` - BaseDomainName string `envconfig:"BASE_DOMAIN_NAME"` - ReleaseName string `envconfig:"RELEASE_NAME"` - TLS struct { - Enabled bool `envconfig:"TLS_ENABLED"` - } - Storage struct { - Size string `envconfig:"USER_TOOLS_STORAGE_SIZE"` - ClassName string `envconfig:"USER_TOOLS_STORAGE_CLASSNAME"` - } - SharedVolume struct { - Name string `envconfig:"SHARED_VOLUME"` - } - MongoDB struct { + Port string `yaml:"port" envconfig:"KDL_SERVER_PORT"` + ProjectMLFlowURL string `envconfig:"PROJECT_MLFLOW_URL"` + ProjectFilebrowserURL string `envconfig:"PROJECT_FILEBROWSER_URL"` + ReleaseName string `envconfig:"RELEASE_NAME"` + StaticFilesPath string `yaml:"staticFilesPath" envconfig:"KDL_SERVER_STATIC_FILES_PATH"` + VSCodeURL string `envconfig:"USER_TOOLS_VSCODE_URL"` + MongoDB struct { URI string `yaml:"uri" envconfig:"KDL_SERVER_MONGODB_URI"` DBName string `yaml:"dbName" envconfig:"KDL_SERVER_MONGODB_NAME"` } `yaml:"mongodb"` @@ -40,91 +31,13 @@ type Config struct { AccessKey string `envconfig:"MINIO_ACCESS_KEY"` SecretKey string `envconfig:"MINIO_SECRET_KEY"` } - VSCode struct { - URL string `envconfig:"USER_TOOLS_VSCODE_URL"` - Enabled bool `envconfig:"USER_TOOLS_VSCODE_ENABLED"` - Image struct { - Repository string `envconfig:"VSCODE_IMG_REPO"` - Tag string `envconfig:"VSCODE_IMG_TAG"` - PullPolicy string `envconfig:"VSCODE_IMG_PULLPOLICY"` - } - } - ProjectMLFlow struct { - URL string `envconfig:"PROJECT_MLFLOW_URL"` - Image struct { - Repository string `envconfig:"PROJECT_MLFLOW_IMG_REPO"` - Tag string `envconfig:"PROJECT_MLFLOW_IMG_TAG"` - PullPolicy string `envconfig:"PROJECT_MLFLOW_IMG_PULLPOLICY"` - } - Ingress struct { - ClassName string `envconfig:"PROJECT_MLFLOW_INGRESS_CLASS_NAME"` - Annotations string `envconfig:"PROJECT_MLFLOW_ENCODED_INGRESS_ANNOTATIONS"` - TLS struct { - SecretName *string `envconfig:"PROJECT_MLFLOW_INGRESS_TLS_SECRET_NAME"` - } - } - NodeSelector string `envconfig:"PROJECT_MLFLOW_NODESELECTOR"` - Affinity string `envconfig:"PROJECT_MLFLOW_AFFINITY"` - Tolerations string `envconfig:"PROJECT_MLFLOW_TOLERATIONS"` - Volume struct { - StorageClassName string `envconfig:"PROJECT_MLFLOW_STORAGE_CLASS_NAME"` - Size string `envconfig:"PROJECT_MLFLOW_STORAGE_SIZE"` - } - } - ProjectFilebrowser struct { - URL string `envconfig:"PROJECT_FILEBROWSER_URL"` - Image struct { - Repository string `envconfig:"PROJECT_FILEBROWSER_IMG_REPO"` - Tag string `envconfig:"PROJECT_FILEBROWSER_IMG_TAG"` - PullPolicy string `envconfig:"PROJECT_FILEBROWSER_IMG_PULLPOLICY"` - } - NodeSelector string `envconfig:"PROJECT_FILEBROWSER_NODESELECTOR"` - Affinity string `envconfig:"PROJECT_FILEBROWSER_AFFINITY"` - Tolerations string `envconfig:"PROJECT_FILEBROWSER_TOLERATIONS"` - } Kg struct { Enabled bool `envconfig:"KNOWLEDGE_GALAXY_ENABLED"` URL string `envconfig:"KNOWLEDGE_GALAXY_URL"` } - OAuth2Proxy struct { - Image struct { - Repository string `envconfig:"OAUTH2_PROXY_IMG_REPO"` - Tag string `envconfig:"OAUTH2_PROXY_IMG_TAG"` - PullPolicy string `envconfig:"OAUTH2_PROXY_IMG_PULLPOLICY"` - } - } - RepoCloner struct { - Image struct { - Repository string `envconfig:"REPO_CLONER_IMG_REPO"` - Tag string `envconfig:"REPO_CLONER_IMG_TAG"` - PullPolicy string `envconfig:"REPO_CLONER_IMG_PULLPOLICY"` - } - } - UserToolsOAuth2Proxy struct { - Image struct { - Repository string `envconfig:"USER_TOOLS_OAUTH2_PROXY_IMG_REPO"` - Tag string `envconfig:"USER_TOOLS_OAUTH2_PROXY_IMG_TAG"` - PullPolicy string `envconfig:"USER_TOOLS_OAUTH2_PROXY_IMG_PULLPOLICY"` - } - } - UserToolsKubeconfig struct { - Enabled bool `envconfig:"USER_TOOLS_KUBECONFIG_DOWNLOAD_ENABLED"` - ExternalServerURL string `envconfig:"USER_TOOLS_KUBECONFIG_EXTERNAL_SERVER_URL"` - } - UserToolsVsCodeRuntime struct { - Image struct { - Repository string `envconfig:"USER_TOOLS_VSCODE_RUNTIME_IMG_REPO"` - Tag string `envconfig:"USER_TOOLS_VSCODE_RUNTIME_IMG_TAG"` - PullPolicy string `envconfig:"USER_TOOLS_VSCODE_RUNTIME_IMG_PULLPOLICY"` - } - } - UserToolsIngress struct { - // Base64 encoded string of the ingress annotations - Annotations string `envconfig:"USER_TOOLS_ENCODED_INGRESS_ANNOTATIONS"` - ClassName string `envconfig:"USER_TOOLS_INGRESS_CLASS_NAME"` - TLS struct { - SecretName *string `envconfig:"USER_TOOLS_TLS_SECRET_NAME"` - } + Kubeconfig struct { + Enabled bool `envconfig:"KUBECONFIG_DOWNLOAD_ENABLED"` + ExternalServerURL string `envconfig:"KUBECONFIG_EXTERNAL_SERVER_URL"` } Labels struct { Common struct { diff --git a/app/api/infrastructure/graph/generated/generated.go b/app/api/infrastructure/graph/generated/generated.go index 1ddc1d838..06fedfaa7 100644 --- a/app/api/infrastructure/graph/generated/generated.go +++ b/app/api/infrastructure/graph/generated/generated.go @@ -233,7 +233,7 @@ func (e *executableSchema) Schema() *ast.Schema { return parsedSchema } -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { +func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]any) (int, bool) { ec := executionContext{nil, e, 0, 0, nil} _ = ec switch typeName + "." + field { @@ -1167,9 +1167,9 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** -func (ec *executionContext) field_Mutation_addApiToken_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_addApiToken_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_addApiToken_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1179,7 +1179,7 @@ func (ec *executionContext) field_Mutation_addApiToken_args(ctx context.Context, } func (ec *executionContext) field_Mutation_addApiToken_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (*model.APITokenInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1199,9 +1199,9 @@ func (ec *executionContext) field_Mutation_addApiToken_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_addMembers_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_addMembers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_addMembers_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1211,7 +1211,7 @@ func (ec *executionContext) field_Mutation_addMembers_args(ctx context.Context, } func (ec *executionContext) field_Mutation_addMembers_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.AddMembersInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1231,9 +1231,9 @@ func (ec *executionContext) field_Mutation_addMembers_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_createProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_createProject_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_createProject_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1243,7 +1243,7 @@ func (ec *executionContext) field_Mutation_createProject_args(ctx context.Contex } func (ec *executionContext) field_Mutation_createProject_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.CreateProjectInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1263,9 +1263,9 @@ func (ec *executionContext) field_Mutation_createProject_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_deleteProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_deleteProject_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_deleteProject_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1275,7 +1275,7 @@ func (ec *executionContext) field_Mutation_deleteProject_args(ctx context.Contex } func (ec *executionContext) field_Mutation_deleteProject_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.DeleteProjectInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1295,9 +1295,9 @@ func (ec *executionContext) field_Mutation_deleteProject_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_removeApiToken_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_removeApiToken_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_removeApiToken_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1307,7 +1307,7 @@ func (ec *executionContext) field_Mutation_removeApiToken_args(ctx context.Conte } func (ec *executionContext) field_Mutation_removeApiToken_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (*model.RemoveAPITokenInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1327,9 +1327,9 @@ func (ec *executionContext) field_Mutation_removeApiToken_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_removeMembers_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_removeMembers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_removeMembers_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1339,7 +1339,7 @@ func (ec *executionContext) field_Mutation_removeMembers_args(ctx context.Contex } func (ec *executionContext) field_Mutation_removeMembers_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.RemoveMembersInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1359,9 +1359,9 @@ func (ec *executionContext) field_Mutation_removeMembers_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_removeUsers_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_removeUsers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_removeUsers_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1371,7 +1371,7 @@ func (ec *executionContext) field_Mutation_removeUsers_args(ctx context.Context, } func (ec *executionContext) field_Mutation_removeUsers_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.RemoveUsersInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1391,9 +1391,9 @@ func (ec *executionContext) field_Mutation_removeUsers_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_setActiveUserTools_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_setActiveUserTools_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_setActiveUserTools_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1403,7 +1403,7 @@ func (ec *executionContext) field_Mutation_setActiveUserTools_args(ctx context.C } func (ec *executionContext) field_Mutation_setActiveUserTools_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.SetActiveUserToolsInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1423,9 +1423,9 @@ func (ec *executionContext) field_Mutation_setActiveUserTools_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_updateAccessLevel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_updateAccessLevel_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_updateAccessLevel_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1435,7 +1435,7 @@ func (ec *executionContext) field_Mutation_updateAccessLevel_args(ctx context.Co } func (ec *executionContext) field_Mutation_updateAccessLevel_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.UpdateAccessLevelInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1455,9 +1455,9 @@ func (ec *executionContext) field_Mutation_updateAccessLevel_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_updateMembers_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_updateMembers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_updateMembers_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1467,7 +1467,7 @@ func (ec *executionContext) field_Mutation_updateMembers_args(ctx context.Contex } func (ec *executionContext) field_Mutation_updateMembers_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.UpdateMembersInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1487,9 +1487,9 @@ func (ec *executionContext) field_Mutation_updateMembers_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Mutation_updateProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_updateProject_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Mutation_updateProject_argsInput(ctx, rawArgs) if err != nil { return nil, err @@ -1499,7 +1499,7 @@ func (ec *executionContext) field_Mutation_updateProject_args(ctx context.Contex } func (ec *executionContext) field_Mutation_updateProject_argsInput( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (model.UpdateProjectInput, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1519,9 +1519,9 @@ func (ec *executionContext) field_Mutation_updateProject_argsInput( return zeroVal, nil } -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Query___type_argsName(ctx, rawArgs) if err != nil { return nil, err @@ -1531,7 +1531,7 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs } func (ec *executionContext) field_Query___type_argsName( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (string, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1551,9 +1551,9 @@ func (ec *executionContext) field_Query___type_argsName( return zeroVal, nil } -func (ec *executionContext) field_Query_project_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query_project_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Query_project_argsID(ctx, rawArgs) if err != nil { return nil, err @@ -1563,7 +1563,7 @@ func (ec *executionContext) field_Query_project_args(ctx context.Context, rawArg } func (ec *executionContext) field_Query_project_argsID( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (string, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1583,9 +1583,9 @@ func (ec *executionContext) field_Query_project_argsID( return zeroVal, nil } -func (ec *executionContext) field_Query_qualityProjectDesc_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Query_qualityProjectDesc_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field_Query_qualityProjectDesc_argsDescription(ctx, rawArgs) if err != nil { return nil, err @@ -1595,7 +1595,7 @@ func (ec *executionContext) field_Query_qualityProjectDesc_args(ctx context.Cont } func (ec *executionContext) field_Query_qualityProjectDesc_argsDescription( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (string, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1615,9 +1615,9 @@ func (ec *executionContext) field_Query_qualityProjectDesc_argsDescription( return zeroVal, nil } -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field___Type_enumValues_argsIncludeDeprecated(ctx, rawArgs) if err != nil { return nil, err @@ -1627,7 +1627,7 @@ func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, ra } func (ec *executionContext) field___Type_enumValues_argsIncludeDeprecated( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (bool, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1647,9 +1647,9 @@ func (ec *executionContext) field___Type_enumValues_argsIncludeDeprecated( return zeroVal, nil } -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error - args := map[string]interface{}{} + args := map[string]any{} arg0, err := ec.field___Type_fields_argsIncludeDeprecated(ctx, rawArgs) if err != nil { return nil, err @@ -1659,7 +1659,7 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg } func (ec *executionContext) field___Type_fields_argsIncludeDeprecated( ctx context.Context, - rawArgs map[string]interface{}, + rawArgs map[string]any, ) (bool, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives @@ -1699,7 +1699,7 @@ func (ec *executionContext) _ApiToken_id(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -1743,7 +1743,7 @@ func (ec *executionContext) _ApiToken_name(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -1787,7 +1787,7 @@ func (ec *executionContext) _ApiToken_creationDate(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.CreationDate, nil }) @@ -1831,7 +1831,7 @@ func (ec *executionContext) _ApiToken_lastUsedDate(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.LastUsedDate, nil }) @@ -1875,7 +1875,7 @@ func (ec *executionContext) _ApiToken_token(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Token, nil }) @@ -1919,7 +1919,7 @@ func (ec *executionContext) _Capability_id(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -1963,7 +1963,7 @@ func (ec *executionContext) _Capability_name(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -2007,7 +2007,7 @@ func (ec *executionContext) _Capability_default(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Default, nil }) @@ -2051,7 +2051,7 @@ func (ec *executionContext) _Member_user(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Member().User(rctx, obj) }) @@ -2115,7 +2115,7 @@ func (ec *executionContext) _Member_accessLevel(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AccessLevel, nil }) @@ -2159,7 +2159,7 @@ func (ec *executionContext) _Member_addedDate(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Member().AddedDate(rctx, obj) }) @@ -2203,7 +2203,7 @@ func (ec *executionContext) _Mutation_removeUsers(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().RemoveUsers(rctx, fc.Args["input"].(model.RemoveUsersInput)) }) @@ -2278,7 +2278,7 @@ func (ec *executionContext) _Mutation_updateAccessLevel(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().UpdateAccessLevel(rctx, fc.Args["input"].(model.UpdateAccessLevelInput)) }) @@ -2353,7 +2353,7 @@ func (ec *executionContext) _Mutation_regenerateSSHKey(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().RegenerateSSHKey(rctx) }) @@ -2417,7 +2417,7 @@ func (ec *executionContext) _Mutation_createProject(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().CreateProject(rctx, fc.Args["input"].(model.CreateProjectInput)) }) @@ -2498,7 +2498,7 @@ func (ec *executionContext) _Mutation_updateProject(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().UpdateProject(rctx, fc.Args["input"].(model.UpdateProjectInput)) }) @@ -2579,7 +2579,7 @@ func (ec *executionContext) _Mutation_deleteProject(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().DeleteProject(rctx, fc.Args["input"].(model.DeleteProjectInput)) }) @@ -2657,7 +2657,7 @@ func (ec *executionContext) _Mutation_addMembers(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().AddMembers(rctx, fc.Args["input"].(model.AddMembersInput)) }) @@ -2738,7 +2738,7 @@ func (ec *executionContext) _Mutation_removeMembers(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().RemoveMembers(rctx, fc.Args["input"].(model.RemoveMembersInput)) }) @@ -2819,7 +2819,7 @@ func (ec *executionContext) _Mutation_updateMembers(ctx context.Context, field g ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().UpdateMembers(rctx, fc.Args["input"].(model.UpdateMembersInput)) }) @@ -2900,7 +2900,7 @@ func (ec *executionContext) _Mutation_addApiToken(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().AddAPIToken(rctx, fc.Args["input"].(*model.APITokenInput)) }) @@ -2964,7 +2964,7 @@ func (ec *executionContext) _Mutation_removeApiToken(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().RemoveAPIToken(rctx, fc.Args["input"].(*model.RemoveAPITokenInput)) }) @@ -3031,7 +3031,7 @@ func (ec *executionContext) _Mutation_setActiveUserTools(ctx context.Context, fi ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().SetActiveUserTools(rctx, fc.Args["input"].(model.SetActiveUserToolsInput)) }) @@ -3106,7 +3106,7 @@ func (ec *executionContext) _Project_id(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -3150,7 +3150,7 @@ func (ec *executionContext) _Project_name(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -3194,7 +3194,7 @@ func (ec *executionContext) _Project_description(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description, nil }) @@ -3238,7 +3238,7 @@ func (ec *executionContext) _Project_favorite(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Favorite, nil }) @@ -3282,7 +3282,7 @@ func (ec *executionContext) _Project_repository(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Repository, nil }) @@ -3331,7 +3331,7 @@ func (ec *executionContext) _Project_creationDate(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Project().CreationDate(rctx, obj) }) @@ -3375,7 +3375,7 @@ func (ec *executionContext) _Project_lastActivationDate(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.LastActivationDate, nil }) @@ -3419,7 +3419,7 @@ func (ec *executionContext) _Project_error(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Error, nil }) @@ -3460,7 +3460,7 @@ func (ec *executionContext) _Project_members(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Members, nil }) @@ -3512,7 +3512,7 @@ func (ec *executionContext) _Project_toolUrls(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Project().ToolUrls(rctx, obj) }) @@ -3566,7 +3566,7 @@ func (ec *executionContext) _Project_needAccess(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Project().NeedAccess(rctx, obj) }) @@ -3610,7 +3610,7 @@ func (ec *executionContext) _Project_archived(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Archived, nil }) @@ -3654,7 +3654,7 @@ func (ec *executionContext) _QualityProjectDesc_quality(ctx context.Context, fie ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Quality, nil }) @@ -3698,7 +3698,7 @@ func (ec *executionContext) _Query_me(ctx context.Context, field graphql.Collect ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Me(rctx) }) @@ -3762,7 +3762,7 @@ func (ec *executionContext) _Query_projects(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Projects(rctx) }) @@ -3832,7 +3832,7 @@ func (ec *executionContext) _Query_project(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Project(rctx, fc.Args["id"].(string)) }) @@ -3913,7 +3913,7 @@ func (ec *executionContext) _Query_users(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Users(rctx) }) @@ -3977,7 +3977,7 @@ func (ec *executionContext) _Query_qualityProjectDesc(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().QualityProjectDesc(rctx, fc.Args["description"].(string)) }) @@ -4036,7 +4036,7 @@ func (ec *executionContext) _Query_runtimes(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Runtimes(rctx) }) @@ -4096,7 +4096,7 @@ func (ec *executionContext) _Query_runningRuntime(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().RunningRuntime(rctx) }) @@ -4153,7 +4153,7 @@ func (ec *executionContext) _Query_capabilities(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Capabilities(rctx) }) @@ -4205,7 +4205,7 @@ func (ec *executionContext) _Query_runningCapability(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().RunningCapability(rctx) }) @@ -4254,7 +4254,7 @@ func (ec *executionContext) _Query_kubeconfig(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().Kubeconfig(rctx) }) @@ -4298,7 +4298,7 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.introspectType(fc.Args["name"].(string)) }) @@ -4372,7 +4372,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.introspectSchema() }) @@ -4427,7 +4427,7 @@ func (ec *executionContext) _Repository_type(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Type, nil }) @@ -4471,7 +4471,7 @@ func (ec *executionContext) _Repository_url(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.Repository().URL(rctx, obj) }) @@ -4515,7 +4515,7 @@ func (ec *executionContext) _Repository_error(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Error, nil }) @@ -4556,7 +4556,7 @@ func (ec *executionContext) _Runtime_id(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -4600,7 +4600,7 @@ func (ec *executionContext) _Runtime_name(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -4644,7 +4644,7 @@ func (ec *executionContext) _Runtime_desc(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Desc, nil }) @@ -4688,7 +4688,7 @@ func (ec *executionContext) _Runtime_labels(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Labels, nil }) @@ -4729,7 +4729,7 @@ func (ec *executionContext) _Runtime_dockerImage(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DockerImage, nil }) @@ -4773,7 +4773,7 @@ func (ec *executionContext) _Runtime_dockerTag(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DockerTag, nil }) @@ -4817,7 +4817,7 @@ func (ec *executionContext) _Runtime_runtimePod(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.RuntimePod, nil }) @@ -4861,7 +4861,7 @@ func (ec *executionContext) _SSHKey_public(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Public, nil }) @@ -4905,7 +4905,7 @@ func (ec *executionContext) _SSHKey_private(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Private, nil }) @@ -4949,7 +4949,7 @@ func (ec *executionContext) _SSHKey_creationDate(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.SSHKey().CreationDate(rctx, obj) }) @@ -4993,7 +4993,7 @@ func (ec *executionContext) _SSHKey_lastActivity(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.SSHKey().LastActivity(rctx, obj) }) @@ -5034,7 +5034,7 @@ func (ec *executionContext) _ToolUrls_knowledgeGalaxy(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.KnowledgeGalaxy, nil }) @@ -5078,7 +5078,7 @@ func (ec *executionContext) _ToolUrls_filebrowser(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Filebrowser, nil }) @@ -5122,7 +5122,7 @@ func (ec *executionContext) _ToolUrls_vscode(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.VSCode, nil }) @@ -5166,7 +5166,7 @@ func (ec *executionContext) _ToolUrls_mlflow(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MLFlow, nil }) @@ -5210,7 +5210,7 @@ func (ec *executionContext) _Topic_name(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -5254,7 +5254,7 @@ func (ec *executionContext) _Topic_relevance(ctx context.Context, field graphql. ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Relevance, nil }) @@ -5298,7 +5298,7 @@ func (ec *executionContext) _User_id(ctx context.Context, field graphql.Collecte ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.ID, nil }) @@ -5342,7 +5342,7 @@ func (ec *executionContext) _User_username(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Username, nil }) @@ -5386,7 +5386,7 @@ func (ec *executionContext) _User_email(ctx context.Context, field graphql.Colle ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Email, nil }) @@ -5430,7 +5430,7 @@ func (ec *executionContext) _User_creationDate(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.User().CreationDate(rctx, obj) }) @@ -5474,7 +5474,7 @@ func (ec *executionContext) _User_accessLevel(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.AccessLevel, nil }) @@ -5518,7 +5518,7 @@ func (ec *executionContext) _User_lastActivity(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.User().LastActivity(rctx, obj) }) @@ -5559,7 +5559,7 @@ func (ec *executionContext) _User_apiTokens(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.APITokens, nil }) @@ -5615,7 +5615,7 @@ func (ec *executionContext) _User_isKubeconfigEnabled(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return ec.resolvers.User().IsKubeconfigEnabled(rctx, obj) }) @@ -5659,7 +5659,7 @@ func (ec *executionContext) _User_sshKey(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SSHKey, nil }) @@ -5713,7 +5713,7 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -5757,7 +5757,7 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -5798,7 +5798,7 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Locations, nil }) @@ -5842,7 +5842,7 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Args, nil }) @@ -5896,7 +5896,7 @@ func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsRepeatable, nil }) @@ -5940,7 +5940,7 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -5984,7 +5984,7 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -6025,7 +6025,7 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsDeprecated(), nil }) @@ -6069,7 +6069,7 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DeprecationReason(), nil }) @@ -6110,7 +6110,7 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -6154,7 +6154,7 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -6195,7 +6195,7 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Args, nil }) @@ -6249,7 +6249,7 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Type, nil }) @@ -6315,7 +6315,7 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.IsDeprecated(), nil }) @@ -6359,7 +6359,7 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DeprecationReason(), nil }) @@ -6400,7 +6400,7 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name, nil }) @@ -6444,7 +6444,7 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -6485,7 +6485,7 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Type, nil }) @@ -6551,7 +6551,7 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.DefaultValue, nil }) @@ -6592,7 +6592,7 @@ func (ec *executionContext) ___Schema_description(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -6633,7 +6633,7 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Types(), nil }) @@ -6699,7 +6699,7 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.QueryType(), nil }) @@ -6765,7 +6765,7 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.MutationType(), nil }) @@ -6828,7 +6828,7 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SubscriptionType(), nil }) @@ -6891,7 +6891,7 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Directives(), nil }) @@ -6947,7 +6947,7 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Kind(), nil }) @@ -6991,7 +6991,7 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Name(), nil }) @@ -7032,7 +7032,7 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Description(), nil }) @@ -7073,7 +7073,7 @@ func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil }) @@ -7139,7 +7139,7 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.Interfaces(), nil }) @@ -7202,7 +7202,7 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.PossibleTypes(), nil }) @@ -7265,7 +7265,7 @@ func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphq ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil }) @@ -7327,7 +7327,7 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.InputFields(), nil }) @@ -7378,7 +7378,7 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.OfType(), nil }) @@ -7441,7 +7441,7 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr ret = graphql.Null } }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children return obj.SpecifiedByURL(), nil }) @@ -7474,10 +7474,10 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context // region **************************** input.gotpl ***************************** -func (ec *executionContext) unmarshalInputAddMembersInput(ctx context.Context, obj interface{}) (model.AddMembersInput, error) { +func (ec *executionContext) unmarshalInputAddMembersInput(ctx context.Context, obj any) (model.AddMembersInput, error) { var it model.AddMembersInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7508,10 +7508,10 @@ func (ec *executionContext) unmarshalInputAddMembersInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputAddUserInput(ctx context.Context, obj interface{}) (model.AddUserInput, error) { +func (ec *executionContext) unmarshalInputAddUserInput(ctx context.Context, obj any) (model.AddUserInput, error) { var it model.AddUserInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7556,10 +7556,10 @@ func (ec *executionContext) unmarshalInputAddUserInput(ctx context.Context, obj return it, nil } -func (ec *executionContext) unmarshalInputApiTokenInput(ctx context.Context, obj interface{}) (model.APITokenInput, error) { +func (ec *executionContext) unmarshalInputApiTokenInput(ctx context.Context, obj any) (model.APITokenInput, error) { var it model.APITokenInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7590,10 +7590,10 @@ func (ec *executionContext) unmarshalInputApiTokenInput(ctx context.Context, obj return it, nil } -func (ec *executionContext) unmarshalInputCreateProjectInput(ctx context.Context, obj interface{}) (model.CreateProjectInput, error) { +func (ec *executionContext) unmarshalInputCreateProjectInput(ctx context.Context, obj any) (model.CreateProjectInput, error) { var it model.CreateProjectInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7638,10 +7638,10 @@ func (ec *executionContext) unmarshalInputCreateProjectInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputDeleteProjectInput(ctx context.Context, obj interface{}) (model.DeleteProjectInput, error) { +func (ec *executionContext) unmarshalInputDeleteProjectInput(ctx context.Context, obj any) (model.DeleteProjectInput, error) { var it model.DeleteProjectInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7665,10 +7665,10 @@ func (ec *executionContext) unmarshalInputDeleteProjectInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputExternalRepositoryInput(ctx context.Context, obj interface{}) (model.ExternalRepositoryInput, error) { +func (ec *executionContext) unmarshalInputExternalRepositoryInput(ctx context.Context, obj any) (model.ExternalRepositoryInput, error) { var it model.ExternalRepositoryInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7713,10 +7713,10 @@ func (ec *executionContext) unmarshalInputExternalRepositoryInput(ctx context.Co return it, nil } -func (ec *executionContext) unmarshalInputRemoveApiTokenInput(ctx context.Context, obj interface{}) (model.RemoveAPITokenInput, error) { +func (ec *executionContext) unmarshalInputRemoveApiTokenInput(ctx context.Context, obj any) (model.RemoveAPITokenInput, error) { var it model.RemoveAPITokenInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7740,10 +7740,10 @@ func (ec *executionContext) unmarshalInputRemoveApiTokenInput(ctx context.Contex return it, nil } -func (ec *executionContext) unmarshalInputRemoveMembersInput(ctx context.Context, obj interface{}) (model.RemoveMembersInput, error) { +func (ec *executionContext) unmarshalInputRemoveMembersInput(ctx context.Context, obj any) (model.RemoveMembersInput, error) { var it model.RemoveMembersInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7774,10 +7774,10 @@ func (ec *executionContext) unmarshalInputRemoveMembersInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputRemoveUsersInput(ctx context.Context, obj interface{}) (model.RemoveUsersInput, error) { +func (ec *executionContext) unmarshalInputRemoveUsersInput(ctx context.Context, obj any) (model.RemoveUsersInput, error) { var it model.RemoveUsersInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7801,10 +7801,10 @@ func (ec *executionContext) unmarshalInputRemoveUsersInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputRepositoryInput(ctx context.Context, obj interface{}) (model.RepositoryInput, error) { +func (ec *executionContext) unmarshalInputRepositoryInput(ctx context.Context, obj any) (model.RepositoryInput, error) { var it model.RepositoryInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7835,10 +7835,10 @@ func (ec *executionContext) unmarshalInputRepositoryInput(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputSetActiveUserToolsInput(ctx context.Context, obj interface{}) (model.SetActiveUserToolsInput, error) { +func (ec *executionContext) unmarshalInputSetActiveUserToolsInput(ctx context.Context, obj any) (model.SetActiveUserToolsInput, error) { var it model.SetActiveUserToolsInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7876,10 +7876,10 @@ func (ec *executionContext) unmarshalInputSetActiveUserToolsInput(ctx context.Co return it, nil } -func (ec *executionContext) unmarshalInputSetBoolFieldInput(ctx context.Context, obj interface{}) (model.SetBoolFieldInput, error) { +func (ec *executionContext) unmarshalInputSetBoolFieldInput(ctx context.Context, obj any) (model.SetBoolFieldInput, error) { var it model.SetBoolFieldInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7910,10 +7910,10 @@ func (ec *executionContext) unmarshalInputSetBoolFieldInput(ctx context.Context, return it, nil } -func (ec *executionContext) unmarshalInputUpdateAccessLevelInput(ctx context.Context, obj interface{}) (model.UpdateAccessLevelInput, error) { +func (ec *executionContext) unmarshalInputUpdateAccessLevelInput(ctx context.Context, obj any) (model.UpdateAccessLevelInput, error) { var it model.UpdateAccessLevelInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7944,10 +7944,10 @@ func (ec *executionContext) unmarshalInputUpdateAccessLevelInput(ctx context.Con return it, nil } -func (ec *executionContext) unmarshalInputUpdateMembersInput(ctx context.Context, obj interface{}) (model.UpdateMembersInput, error) { +func (ec *executionContext) unmarshalInputUpdateMembersInput(ctx context.Context, obj any) (model.UpdateMembersInput, error) { var it model.UpdateMembersInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -7985,10 +7985,10 @@ func (ec *executionContext) unmarshalInputUpdateMembersInput(ctx context.Context return it, nil } -func (ec *executionContext) unmarshalInputUpdateProjectInput(ctx context.Context, obj interface{}) (model.UpdateProjectInput, error) { +func (ec *executionContext) unmarshalInputUpdateProjectInput(ctx context.Context, obj any) (model.UpdateProjectInput, error) { var it model.UpdateProjectInput - asMap := map[string]interface{}{} - for k, v := range obj.(map[string]interface{}) { + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { asMap[k] = v } @@ -9713,7 +9713,7 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o // region ***************************** type.gotpl ***************************** -func (ec *executionContext) unmarshalNAccessLevel2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐAccessLevel(ctx context.Context, v interface{}) (entity.AccessLevel, error) { +func (ec *executionContext) unmarshalNAccessLevel2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐAccessLevel(ctx context.Context, v any) (entity.AccessLevel, error) { tmp, err := graphql.UnmarshalString(v) res := entity.AccessLevel(tmp) return res, graphql.ErrorOnPath(ctx, err) @@ -9729,7 +9729,7 @@ func (ec *executionContext) marshalNAccessLevel2githubᚗcomᚋkonstellationᚑi return res } -func (ec *executionContext) unmarshalNAddMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐAddMembersInput(ctx context.Context, v interface{}) (model.AddMembersInput, error) { +func (ec *executionContext) unmarshalNAddMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐAddMembersInput(ctx context.Context, v any) (model.AddMembersInput, error) { res, err := ec.unmarshalInputAddMembersInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } @@ -9792,7 +9792,7 @@ func (ec *executionContext) marshalNApiToken2ᚖgithubᚗcomᚋkonstellationᚑi return ec._ApiToken(ctx, sel, v) } -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { +func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -9855,17 +9855,17 @@ func (ec *executionContext) marshalNCapability2ᚕgithubᚗcomᚋkonstellation return ret } -func (ec *executionContext) unmarshalNCreateProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐCreateProjectInput(ctx context.Context, v interface{}) (model.CreateProjectInput, error) { +func (ec *executionContext) unmarshalNCreateProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐCreateProjectInput(ctx context.Context, v any) (model.CreateProjectInput, error) { res, err := ec.unmarshalInputCreateProjectInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNDeleteProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐDeleteProjectInput(ctx context.Context, v interface{}) (model.DeleteProjectInput, error) { +func (ec *executionContext) unmarshalNDeleteProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐDeleteProjectInput(ctx context.Context, v any) (model.DeleteProjectInput, error) { res, err := ec.unmarshalInputDeleteProjectInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { +func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v any) (float64, error) { res, err := graphql.UnmarshalFloatContext(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } @@ -9880,7 +9880,7 @@ func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.S return graphql.WrapContextMarshaler(ctx, res) } -func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalNID2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalID(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -9895,8 +9895,8 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec return res } -func (ec *executionContext) unmarshalNID2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} +func (ec *executionContext) unmarshalNID2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { + var vSlice []any if v != nil { vSlice = graphql.CoerceList(v) } @@ -9927,7 +9927,7 @@ func (ec *executionContext) marshalNID2ᚕstringᚄ(ctx context.Context, sel ast return ret } -func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { +func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v any) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10062,17 +10062,17 @@ func (ec *executionContext) marshalNQualityProjectDesc2ᚖgithubᚗcomᚋkonstel return ec._QualityProjectDesc(ctx, sel, v) } -func (ec *executionContext) unmarshalNRemoveMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveMembersInput(ctx context.Context, v interface{}) (model.RemoveMembersInput, error) { +func (ec *executionContext) unmarshalNRemoveMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveMembersInput(ctx context.Context, v any) (model.RemoveMembersInput, error) { res, err := ec.unmarshalInputRemoveMembersInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNRemoveUsersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveUsersInput(ctx context.Context, v interface{}) (model.RemoveUsersInput, error) { +func (ec *executionContext) unmarshalNRemoveUsersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveUsersInput(ctx context.Context, v any) (model.RemoveUsersInput, error) { res, err := ec.unmarshalInputRemoveUsersInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNRepositoryAuthMethod2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐRepositoryAuthMethod(ctx context.Context, v interface{}) (entity.RepositoryAuthMethod, error) { +func (ec *executionContext) unmarshalNRepositoryAuthMethod2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐRepositoryAuthMethod(ctx context.Context, v any) (entity.RepositoryAuthMethod, error) { tmp, err := graphql.UnmarshalString(v) res := entity.RepositoryAuthMethod(tmp) return res, graphql.ErrorOnPath(ctx, err) @@ -10088,12 +10088,12 @@ func (ec *executionContext) marshalNRepositoryAuthMethod2githubᚗcomᚋkonstell return res } -func (ec *executionContext) unmarshalNRepositoryInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRepositoryInput(ctx context.Context, v interface{}) (*model.RepositoryInput, error) { +func (ec *executionContext) unmarshalNRepositoryInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRepositoryInput(ctx context.Context, v any) (*model.RepositoryInput, error) { res, err := ec.unmarshalInputRepositoryInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNRepositoryType2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐRepositoryType(ctx context.Context, v interface{}) (entity.RepositoryType, error) { +func (ec *executionContext) unmarshalNRepositoryType2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋentityᚐRepositoryType(ctx context.Context, v any) (entity.RepositoryType, error) { tmp, err := graphql.UnmarshalString(v) res := entity.RepositoryType(tmp) return res, graphql.ErrorOnPath(ctx, err) @@ -10161,12 +10161,12 @@ func (ec *executionContext) marshalNSSHKey2githubᚗcomᚋkonstellationᚑioᚋk return ec._SSHKey(ctx, sel, &v) } -func (ec *executionContext) unmarshalNSetActiveUserToolsInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐSetActiveUserToolsInput(ctx context.Context, v interface{}) (model.SetActiveUserToolsInput, error) { +func (ec *executionContext) unmarshalNSetActiveUserToolsInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐSetActiveUserToolsInput(ctx context.Context, v any) (model.SetActiveUserToolsInput, error) { res, err := ec.unmarshalInputSetActiveUserToolsInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10195,17 +10195,17 @@ func (ec *executionContext) marshalNToolUrls2ᚖgithubᚗcomᚋkonstellationᚑi return ec._ToolUrls(ctx, sel, v) } -func (ec *executionContext) unmarshalNUpdateAccessLevelInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateAccessLevelInput(ctx context.Context, v interface{}) (model.UpdateAccessLevelInput, error) { +func (ec *executionContext) unmarshalNUpdateAccessLevelInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateAccessLevelInput(ctx context.Context, v any) (model.UpdateAccessLevelInput, error) { res, err := ec.unmarshalInputUpdateAccessLevelInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateMembersInput(ctx context.Context, v interface{}) (model.UpdateMembersInput, error) { +func (ec *executionContext) unmarshalNUpdateMembersInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateMembersInput(ctx context.Context, v any) (model.UpdateMembersInput, error) { res, err := ec.unmarshalInputUpdateMembersInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNUpdateProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateProjectInput(ctx context.Context, v interface{}) (model.UpdateProjectInput, error) { +func (ec *executionContext) unmarshalNUpdateProjectInput2githubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐUpdateProjectInput(ctx context.Context, v any) (model.UpdateProjectInput, error) { res, err := ec.unmarshalInputUpdateProjectInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10316,7 +10316,7 @@ func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgq return ret } -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10331,8 +10331,8 @@ func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Conte return res } -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} +func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { + var vSlice []any if v != nil { vSlice = graphql.CoerceList(v) } @@ -10506,7 +10506,7 @@ func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen return ec.___Type(ctx, sel, v) } -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { +func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10528,7 +10528,7 @@ func (ec *executionContext) marshalOApiToken2ᚖgithubᚗcomᚋkonstellationᚑi return ec._ApiToken(ctx, sel, v) } -func (ec *executionContext) unmarshalOApiTokenInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐAPITokenInput(ctx context.Context, v interface{}) (*model.APITokenInput, error) { +func (ec *executionContext) unmarshalOApiTokenInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐAPITokenInput(ctx context.Context, v any) (*model.APITokenInput, error) { if v == nil { return nil, nil } @@ -10536,7 +10536,7 @@ func (ec *executionContext) unmarshalOApiTokenInput2ᚖgithubᚗcomᚋkonstellat return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { +func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } @@ -10546,7 +10546,7 @@ func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.Se return res } -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { +func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v any) (*bool, error) { if v == nil { return nil, nil } @@ -10569,7 +10569,7 @@ func (ec *executionContext) marshalOCapability2ᚖgithubᚗcomᚋkonstellation return ec._Capability(ctx, sel, v) } -func (ec *executionContext) unmarshalOExternalRepositoryInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐExternalRepositoryInput(ctx context.Context, v interface{}) (*model.ExternalRepositoryInput, error) { +func (ec *executionContext) unmarshalOExternalRepositoryInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐExternalRepositoryInput(ctx context.Context, v any) (*model.ExternalRepositoryInput, error) { if v == nil { return nil, nil } @@ -10584,7 +10584,7 @@ func (ec *executionContext) marshalOProject2ᚖgithubᚗcomᚋkonstellationᚑio return ec._Project(ctx, sel, v) } -func (ec *executionContext) unmarshalORemoveApiTokenInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveAPITokenInput(ctx context.Context, v interface{}) (*model.RemoveAPITokenInput, error) { +func (ec *executionContext) unmarshalORemoveApiTokenInput2ᚖgithubᚗcomᚋkonstellationᚑioᚋkdlᚑserverᚋappᚋapiᚋinfrastructureᚋgraphᚋmodelᚐRemoveAPITokenInput(ctx context.Context, v any) (*model.RemoveAPITokenInput, error) { if v == nil { return nil, nil } @@ -10603,11 +10603,11 @@ func (ec *executionContext) marshalORuntime2ᚖgithubᚗcomᚋkonstellationᚑio return ec._Runtime(ctx, sel, v) } -func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { +func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { if v == nil { return nil, nil } - var vSlice []interface{} + var vSlice []any if v != nil { vSlice = graphql.CoerceList(v) } @@ -10641,7 +10641,7 @@ func (ec *executionContext) marshalOString2ᚕstringᚄ(ctx context.Context, sel return ret } -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { +func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v any) (*string, error) { if v == nil { return nil, nil } diff --git a/app/api/infrastructure/graph/schema.resolvers.go b/app/api/infrastructure/graph/schema.resolvers.go index 2c61b94fe..5973d1e90 100644 --- a/app/api/infrastructure/graph/schema.resolvers.go +++ b/app/api/infrastructure/graph/schema.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.60 +// Code generated by github.com/99designs/gqlgen version v0.17.61 import ( "context" @@ -217,10 +217,10 @@ func (r *projectResolver) ToolUrls(ctx context.Context, obj *entity.Project) (*e folderName := obj.Repository.RepoName - vscodeWithUsername := strings.Replace(r.cfg.VSCode.URL, "USERNAME", slugUserName, 1) + vscodeWithUsername := strings.Replace(r.cfg.VSCodeURL, "USERNAME", slugUserName, 1) vscodeWithUsernameAndFolder := strings.Replace(vscodeWithUsername, "REPO_FOLDER", folderName, 1) - mlflowWithProject := strings.Replace(r.cfg.ProjectMLFlow.URL, "PROJECT_ID", obj.ID, 1) - filebrowserWithProject := strings.Replace(r.cfg.ProjectFilebrowser.URL, "PROJECT_ID", obj.ID, 1) + mlflowWithProject := strings.Replace(r.cfg.ProjectMLFlowURL, "PROJECT_ID", obj.ID, 1) + filebrowserWithProject := strings.Replace(r.cfg.ProjectFilebrowserURL, "PROJECT_ID", obj.ID, 1) kgWithProject := "" if r.cfg.Kg.Enabled { diff --git a/app/api/infrastructure/k8s/client.go b/app/api/infrastructure/k8s/client.go index e06cb5062..57315f972 100644 --- a/app/api/infrastructure/k8s/client.go +++ b/app/api/infrastructure/k8s/client.go @@ -15,35 +15,35 @@ import ( ) const ( - userToolsGroup = "kdl.konstellation.io" - userToolsResource = "usertools" - userToolsVersion = "v1alpha1" - userToolsAPIVersion = userToolsGroup + "/" + userToolsVersion - - kdlprojectGroup = "kdl.konstellation.io" - kdlprojectResource = "kdlprojects" - kdlprojectVersion = "v1" - kdlprojectAPIVersion = kdlprojectGroup + "/" + kdlprojectVersion + kdlUserToolsGroup = "kdl.konstellation.io" + kdlUserToolsResource = "kdlusertools" + kdlUserToolsVersion = "v1" + kdlUserToolsAPIVersion = kdlUserToolsGroup + "/" + kdlUserToolsVersion + + kdlProjectGroup = "kdl.konstellation.io" + kdlProjectResource = "kdlprojects" + kdlProjectVersion = "v1" + kdlProjectAPIVersion = kdlProjectGroup + "/" + kdlProjectVersion ) var _ ClientInterface = (*Client)(nil) type Client struct { - logger logr.Logger - cfg config.Config - clientset *kubernetes.Clientset - userToolsRes dynamic.NamespaceableResourceInterface - kdlprojectRes dynamic.NamespaceableResourceInterface + logger logr.Logger + cfg config.Config + clientset *kubernetes.Clientset + kdlUserToolsRes dynamic.NamespaceableResourceInterface + kdlProjectRes dynamic.NamespaceableResourceInterface } -func New(logger logr.Logger, cfg config.Config, clientset *kubernetes.Clientset, userToolsRes, - kdlprojectRes dynamic.NamespaceableResourceInterface) *Client { +func New(logger logr.Logger, cfg config.Config, clientset *kubernetes.Clientset, kdlUserToolsRes, + kdlProjectRes dynamic.NamespaceableResourceInterface) *Client { return &Client{ - logger: logger, - cfg: cfg, - clientset: clientset, - userToolsRes: userToolsRes, - kdlprojectRes: kdlprojectRes, + logger: logger, + cfg: cfg, + clientset: clientset, + kdlUserToolsRes: kdlUserToolsRes, + kdlProjectRes: kdlProjectRes, } } @@ -60,18 +60,19 @@ func NewK8sClient(logger logr.Logger, cfg config.Config) (ClientInterface, error return nil, err } - userToolsRes := dynamicClient.Resource(schema.GroupVersionResource{ - Group: userToolsGroup, - Version: userToolsVersion, - Resource: userToolsResource, + kdlUserToolsRes := dynamicClient.Resource(schema.GroupVersionResource{ + Group: kdlUserToolsGroup, + Version: kdlUserToolsVersion, + Resource: kdlUserToolsResource, }) - kdlprojectRes := dynamicClient.Resource(schema.GroupVersionResource{ - Group: kdlprojectGroup, - Version: kdlprojectVersion, - Resource: kdlprojectResource, + kdlProjectRes := dynamicClient.Resource(schema.GroupVersionResource{ + Group: kdlProjectGroup, + Version: kdlProjectVersion, + Resource: kdlProjectResource, }) - c := New(logger, cfg, clientset, userToolsRes, kdlprojectRes) + + c := New(logger, cfg, clientset, kdlUserToolsRes, kdlProjectRes) return c, nil } diff --git a/app/api/infrastructure/k8s/error.go b/app/api/infrastructure/k8s/error.go new file mode 100644 index 000000000..cc5774b65 --- /dev/null +++ b/app/api/infrastructure/k8s/error.go @@ -0,0 +1,11 @@ +package k8s + +import "errors" + +var errCRDNoMetadata = errors.New("CRD does not have a 'metadata' field") +var errCRDNoSpec = errors.New("CRD does not have a 'spec' field") +var errCRDNoSpecMlflow = errors.New("CRD does not have a 'spec.mlflow' field") +var errCRDNoSpecMlflowEnv = errors.New("CRD does not have a 'spec.mlflow.env' field") +var errCRDNoSpecVscodeRuntime = errors.New("CRD does not have a 'spec.vscodeRuntime' field") +var errCRDNoSpecVscodeRuntimeImage = errors.New("CRD does not have a 'spec.vscodeRuntime.image' field") +var errCRDNoSpecPodLabels = errors.New("CRD does not have a 'spec.podLabels' field") diff --git a/app/api/infrastructure/k8s/interface.go b/app/api/infrastructure/k8s/interface.go index 5ac5299d9..287e56a0a 100644 --- a/app/api/infrastructure/k8s/interface.go +++ b/app/api/infrastructure/k8s/interface.go @@ -15,7 +15,7 @@ type ClientInterface interface { CreateSecret(ctx context.Context, name string, values, labels map[string]string) error UpdateSecret(ctx context.Context, name string, values, labels map[string]string) error GetSecret(ctx context.Context, name string) (map[string][]byte, error) - CreateUserToolsCR(ctx context.Context, username, runtimeID, runtimeImage, runtimeTag string, capabilities entity.Capabilities) error + CreateUserToolsCR(ctx context.Context, username string, data UserToolsData) error DeleteUserToolsCR(ctx context.Context, username string) error IsUserToolPODRunning(ctx context.Context, username string) (bool, error) GetRuntimeIDFromUserTools(ctx context.Context, username string) (string, error) diff --git a/app/api/infrastructure/k8s/k8smap.go b/app/api/infrastructure/k8s/k8smap.go deleted file mode 100644 index efb29540a..000000000 --- a/app/api/infrastructure/k8s/k8smap.go +++ /dev/null @@ -1,24 +0,0 @@ -package k8s - -import ( - "encoding/base64" - "fmt" - - "gopkg.in/yaml.v3" -) - -func (k *Client) getK8sMap(base64Map string) (map[string]interface{}, error) { - decodedMap, err := base64.StdEncoding.DecodeString(base64Map) - if err != nil { - return nil, fmt.Errorf("error decoding map: %w", err) - } - - var k8sMap map[string]interface{} - - err = yaml.Unmarshal(decodedMap, &k8sMap) - if err != nil { - return nil, fmt.Errorf("error unmarshaling map: %w", err) - } - - return k8sMap, nil -} diff --git a/app/api/infrastructure/k8s/kdlproject.go b/app/api/infrastructure/k8s/kdlproject.go index abad08d3d..8fdfe751a 100644 --- a/app/api/infrastructure/k8s/kdlproject.go +++ b/app/api/infrastructure/k8s/kdlproject.go @@ -2,17 +2,11 @@ package k8s import ( "context" - "errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -var errCRDNoSpec = errors.New("CRD does not have a 'spec' field") -var errCRDNoSpecMlflow = errors.New("CRD does not have a 'spec.mlflow' field") -var errCRDNoSpecMlflowEnv = errors.New("CRD does not have a 'spec.mlflow.env' field") -var errCRDNoMetadata = errors.New("CRD does not have a 'metadata' field") - func (k *Client) CreateKDLProjectCR(ctx context.Context, projectID string) error { // get the CRD template from the ConfigMap configMapKdlProjectName := k.cfg.ReleaseName + "-server-project-template" @@ -65,13 +59,11 @@ func (k *Client) CreateKDLProjectCR(ctx context.Context, projectID string) error // CRD object is now updated and ready to be created k.logger.Info("Creating kdl project") - _, err = k.kdlprojectRes.Namespace(k.cfg.Kubernetes.Namespace).Create( - ctx, - &unstructured.Unstructured{ - Object: crd, - }, - metav1.CreateOptions{}, - ) + definition := &unstructured.Unstructured{ + Object: crd, + } + + _, err = k.kdlProjectRes.Namespace(k.cfg.Kubernetes.Namespace).Create(ctx, definition, metav1.CreateOptions{}) if err != nil { return err } @@ -84,7 +76,7 @@ func (k *Client) CreateKDLProjectCR(ctx context.Context, projectID string) error func (k *Client) DeleteKDLProjectCR(ctx context.Context, projectID string) error { k.logger.Info("Attempting to delete KDL Project CR in k8s", "projectName", projectID) - err := k.kdlprojectRes.Namespace(k.cfg.Kubernetes.Namespace).Delete(ctx, projectID, *metav1.NewDeleteOptions(0)) + err := k.kdlProjectRes.Namespace(k.cfg.Kubernetes.Namespace).Delete(ctx, projectID, *metav1.NewDeleteOptions(0)) if err == nil { k.logger.Info("KDL Project CR correctly deleted in k8s", "projectName", projectID) } diff --git a/app/api/infrastructure/k8s/kubeconfig.go b/app/api/infrastructure/k8s/kubeconfig.go index aa0a64f10..4d43a9f63 100644 --- a/app/api/infrastructure/k8s/kubeconfig.go +++ b/app/api/infrastructure/k8s/kubeconfig.go @@ -46,7 +46,7 @@ apiVersion: v1 clusters: - cluster: certificate-authority-data: ` + base64.StdEncoding.EncodeToString(ca) + ` - server: ` + k.cfg.UserToolsKubeconfig.ExternalServerURL + ` + server: ` + k.cfg.Kubeconfig.ExternalServerURL + ` name: konstellation contexts: - context: diff --git a/app/api/infrastructure/k8s/mocks_interface.go b/app/api/infrastructure/k8s/mocks_interface.go index e921c0dae..3888018e7 100644 --- a/app/api/infrastructure/k8s/mocks_interface.go +++ b/app/api/infrastructure/k8s/mocks_interface.go @@ -94,17 +94,17 @@ func (mr *MockClientInterfaceMockRecorder) CreateUserServiceAccount(ctx, usernam } // CreateUserToolsCR mocks base method. -func (m *MockClientInterface) CreateUserToolsCR(ctx context.Context, username, runtimeID, runtimeImage, runtimeTag string, capabilities entity.Capabilities) error { +func (m *MockClientInterface) CreateUserToolsCR(ctx context.Context, username string, data UserToolsData) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateUserToolsCR", ctx, username, runtimeID, runtimeImage, runtimeTag, capabilities) + ret := m.ctrl.Call(m, "CreateUserToolsCR", ctx, username, data) ret0, _ := ret[0].(error) return ret0 } // CreateUserToolsCR indicates an expected call of CreateUserToolsCR. -func (mr *MockClientInterfaceMockRecorder) CreateUserToolsCR(ctx, username, runtimeID, runtimeImage, runtimeTag, capabilities interface{}) *gomock.Call { +func (mr *MockClientInterfaceMockRecorder) CreateUserToolsCR(ctx, username, data interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserToolsCR", reflect.TypeOf((*MockClientInterface)(nil).CreateUserToolsCR), ctx, username, runtimeID, runtimeImage, runtimeTag, capabilities) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserToolsCR", reflect.TypeOf((*MockClientInterface)(nil).CreateUserToolsCR), ctx, username, data) } // DeleteKDLProjectCR mocks base method. diff --git a/app/api/infrastructure/k8s/suite_test.go b/app/api/infrastructure/k8s/suite_test.go index 414f16295..9ab2004d8 100644 --- a/app/api/infrastructure/k8s/suite_test.go +++ b/app/api/infrastructure/k8s/suite_test.go @@ -20,16 +20,23 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) const ( - namespace = "kdl-test" - releaseName = "kdl" - kdlprojectGroup = "kdl.konstellation.io" - kdlprojectResource = "kdlprojects" - kdlprojectVersion = "v1" - kdlprojectAPIVersion = kdlprojectGroup + "/" + kdlprojectVersion + namespace = "kdl-test" + releaseName = "kdl" + + kdlUserToolsGroup = "kdl.konstellation.io" + kdlUserToolsResource = "kdlusertools" + kdlUserToolsVersion = "v1" + kdlUserToolsAPIVersion = kdlUserToolsGroup + "/" + kdlUserToolsVersion + + kdlProjectGroup = "kdl.konstellation.io" + kdlProjectResource = "kdlprojects" + kdlProjectVersion = "v1" + kdlProjectAPIVersion = kdlProjectGroup + "/" + kdlProjectVersion ) type testSuite struct { @@ -43,6 +50,99 @@ func TestSuite(t *testing.T) { suite.Run(t, new(testSuite)) } +func (s *testSuite) defineCRD(restcfg *rest.Config) { + // Create a clientset for CRD operations + apiExtensionsClient, err := apiextensionsclient.NewForConfig(restcfg) + s.Require().NoError(err) + + // Define the CRD for KDLUserTools + crdKdlUserTools := &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kdlusertools.kdl.konstellation.io", // Format: plural.group + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: "kdl.konstellation.io", + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: "kdlusertools", + Singular: "kdlusertool", + Kind: "KDLUserTools", + ListKind: "KDLUserToolsList", + }, + Scope: apiextensionsv1.NamespaceScoped, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ + { + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "username": {Type: "string"}, + "usernameSlug": {Type: "string"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + + // Create the CRD KDLUserTools in the cluster + _, err = apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crdKdlUserTools, metav1.CreateOptions{}) + s.Require().NoError(err) + + // Define the CRD for KDLProject + crdKdlProject := &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kdlprojects.kdl.konstellation.io", // Format: plural.group + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: "kdl.konstellation.io", + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: "kdlprojects", + Singular: "kdlproject", + Kind: "KDLProject", + ListKind: "KDLProjectList", + }, + Scope: apiextensionsv1.NamespaceScoped, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ + { + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "projectId": { + Type: "string", + }, + }, + Required: []string{"projectId"}, + }, + }, + Required: []string{"spec"}, + }, + }, + }, + }, + }, + } + + // Create the CRD KDLProject in the cluster + _, err = apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crdKdlProject, metav1.CreateOptions{}) + s.Require().NoError(err) +} + func (s *testSuite) SetupSuite() { ctx := context.Background() @@ -84,71 +184,30 @@ func (s *testSuite) SetupSuite() { }, } - // Create a clientset for CRD operations - apiExtensionsClient, err := apiextensionsclient.NewForConfig(restcfg) - s.Require().NoError(err) - dynamicClient, err := dynamic.NewForConfig(restcfg) s.Require().NoError(err) - kdlprojectRes := dynamicClient.Resource(schema.GroupVersionResource{ - Group: kdlprojectGroup, - Version: kdlprojectVersion, - Resource: kdlprojectResource, + kdlUserToolsRes := dynamicClient.Resource(schema.GroupVersionResource{ + Group: kdlUserToolsGroup, + Version: kdlUserToolsVersion, + Resource: kdlUserToolsResource, }) - // Define the CRD - crd := &apiextensionsv1.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kdlprojects.kdl.konstellation.io", // Format: plural.group - }, - Spec: apiextensionsv1.CustomResourceDefinitionSpec{ - Group: "kdl.konstellation.io", - Names: apiextensionsv1.CustomResourceDefinitionNames{ - Plural: "kdlprojects", // Plural name - Singular: "kdlproject", // Singular name - Kind: "KDLProject", // Kind - ListKind: "KDLProjectList", // List kind - }, - Scope: apiextensionsv1.NamespaceScoped, // Namespace scoped - Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ - { - Name: "v1", // Version name - Served: true, // Whether the version is served - Storage: true, // Whether it is the storage version - Schema: &apiextensionsv1.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "spec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "projectId": { - Type: "string", - }, - }, - Required: []string{"projectId"}, // Mark as required - }, - }, - Required: []string{"spec"}, // Spec is required - }, - }, - }, - }, - }, - } + kdlProjectRes := dynamicClient.Resource(schema.GroupVersionResource{ + Group: kdlProjectGroup, + Version: kdlProjectVersion, + Resource: kdlProjectResource, + }) - // Create the CRD in the cluster - _, err = apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) - s.Require().NoError(err) + s.defineCRD(restcfg) // Create the client s.Client = k8s.New( logger, cfg, s.Clientset, - nil, - kdlprojectRes, + kdlUserToolsRes, + kdlProjectRes, ) } diff --git a/app/api/infrastructure/k8s/usertools.go b/app/api/infrastructure/k8s/usertools.go index 312ce0e95..9f9511dec 100644 --- a/app/api/infrastructure/k8s/usertools.go +++ b/app/api/infrastructure/k8s/usertools.go @@ -13,6 +13,13 @@ import ( "k8s.io/apimachinery/pkg/watch" ) +type UserToolsData struct { + RuntimeID string + RuntimeImage string + RuntimeTag string + Capabilities entity.Capabilities +} + // DeleteUserToolsCR removes a given user tools custom resource from Kubernetes. func (k *Client) DeleteUserToolsCR(ctx context.Context, username string) error { slugUsername := k.getSlugUsername(username) @@ -22,7 +29,7 @@ func (k *Client) DeleteUserToolsCR(ctx context.Context, username string) error { delPropagationFg := metav1.DeletePropagationForeground - err := k.userToolsRes.Namespace(k.cfg.Kubernetes.Namespace).Delete(ctx, resName, metav1.DeleteOptions{ + err := k.kdlUserToolsRes.Namespace(k.cfg.Kubernetes.Namespace).Delete(ctx, resName, metav1.DeleteOptions{ GracePeriodSeconds: &zero, PropagationPolicy: &delPropagationFg, }) @@ -32,7 +39,7 @@ func (k *Client) DeleteUserToolsCR(ctx context.Context, username string) error { return err } - result, err := k.userToolsRes. + result, err := k.kdlUserToolsRes. Namespace(k.cfg.Kubernetes.Namespace). Patch(ctx, resName, types.MergePatchType, []byte("{\"metadata\":{\"finalizers\":[]}}"), metav1.PatchOptions{}) @@ -45,17 +52,123 @@ func (k *Client) DeleteUserToolsCR(ctx context.Context, username string) error { return k.waitUserToolsDeleted(ctx, resName) } +func (k *Client) updateUserToolsTemplate( + crd *map[string]interface{}, + slugUsername, resName, username string, + data UserToolsData, +) (*map[string]interface{}, error) { + crdToUpdate := *crd + // update metadata.name and metadata.namespace in the CRD object + metadata, ok := crdToUpdate["metadata"].(map[string]interface{}) + + if !ok { + return nil, errCRDNoMetadata + } + + metadata["name"] = resName + metadata["namespace"] = k.cfg.Kubernetes.Namespace + + // update spec.username and spec.usernameSlug in the CRD object + spec, ok := crdToUpdate["spec"].(map[string]interface{}) + if !ok { + return nil, errCRDNoSpec + } + + spec["username"] = username + spec["usernameSlug"] = slugUsername + + // update spec.vscodeRuntime.image.repository and spec.vscodeRuntime.image.tag in the CRD object + vscodeRuntime, ok := spec["vscodeRuntime"].(map[string]interface{}) + if !ok { + return nil, errCRDNoSpecVscodeRuntime + } + + vscodeRuntimeImage, ok := vscodeRuntime["image"].(map[string]interface{}) + if !ok { + return nil, errCRDNoSpecVscodeRuntimeImage + } + + vscodeRuntimeImage["repository"] = data.RuntimeImage + vscodeRuntimeImage["tag"] = data.RuntimeTag + // FUTURE: update spec.vscodeRuntime.env.MINIO_ACCESS_KEY and spec.vscodeRuntime.env.MINIO_SECRET_KEY with minIO values for the user + + if data.Capabilities.ID != "" { + if err := data.Capabilities.Validate(); err != nil { + return nil, err + } + + // update spec.nodeSelector in the CRD object + if !data.Capabilities.IsNodeSelectorsEmpty() { + spec["nodeSelector"] = data.Capabilities.GetNodeSelectors() + } + + // update spec.tolerations in the CRD object + if !data.Capabilities.IsTolerationsEmpty() { + spec["tolerations"] = data.Capabilities.GetTolerations() + } + + // update spec.affinity in the CRD object + if !data.Capabilities.IsAffinitiesEmpty() { + spec["affinity"] = data.Capabilities.GetAffinities() + } + } + + // update spec.podLabels.runtimeId and spec.podLabels.capabilityId in the CRD object + podLabels, ok := spec["podLabels"].(map[string]interface{}) + if !ok { + return nil, errCRDNoSpecPodLabels + } + + if data.RuntimeID != "" { + podLabels["runtimeId"] = data.RuntimeID + } + + if data.Capabilities.ID != "" { + podLabels["capabilityId"] = data.Capabilities.ID + } + + return &crdToUpdate, nil +} + // CreateUserToolsCR creates the user tools Custom Resource in Kubernetes. -func (k *Client) CreateUserToolsCR(ctx context.Context, username, runtimeID, runtimeImage, runtimeTag string, - capabilities entity.Capabilities) error { +func (k *Client) CreateUserToolsCR( + ctx context.Context, + username string, + data UserToolsData, +) error { slugUsername := k.getSlugUsername(username) resName := fmt.Sprintf("usertools-%s", slugUsername) + configMapKdlProjectName := k.cfg.ReleaseName + "-server-user-tools-template" + + configMap, err := k.GetConfigMap(ctx, configMapKdlProjectName) + if err != nil { + return err + } + + // get the CRD template converted from yaml to go object from the ConfigMap + crd, err := k.getCrdTemplateFromConfigMap(configMap) + if err != nil { + return err + } + + // update the CRD object with correct values + crdUpdated, err := k.updateUserToolsTemplate(&crd, slugUsername, resName, username, data) + if err != nil { + return err + } + + definition := &unstructured.Unstructured{ + Object: *crdUpdated, + } - err := k.createUserToolsDefinition(ctx, username, slugUsername, resName, runtimeID, runtimeImage, runtimeTag, capabilities) + _, err = k.kdlUserToolsRes.Namespace(k.cfg.Kubernetes.Namespace).Create(ctx, definition, metav1.CreateOptions{}) if err != nil { + k.logger.Error(err, "Error creating user tools") return err } + k.logger.Info("Created CRD KDLUserTools object", "resName", resName) + return k.waitUserToolsRunning(ctx, resName) } @@ -141,165 +254,6 @@ func (k *Client) userToolsPODLabelSelector(resName string) string { return fmt.Sprintf("app.kubernetes.io/instance=%s", resName) } -// createUserToolsDefinition creates a new Custom Resource of type UserTools for the given user. -func (k *Client) createUserToolsDefinition(ctx context.Context, username, usernameSlug, resName, runtimeID, - runtimeImage, runtimeTag string, capabilities entity.Capabilities) error { - serviceAccountName := k.getUserServiceAccountName(usernameSlug) - - ingressAnnotations, err := k.getK8sMap(k.cfg.UserToolsIngress.Annotations) - if err != nil { - return fmt.Errorf("error getting ingress annotations: %w", err) - } - - definition, err := k.getUserToolsDefinition( - ingressAnnotations, - resName, - username, - usernameSlug, - runtimeID, - runtimeImage, - runtimeTag, - serviceAccountName, - capabilities, - ) - - if err != nil { - k.logger.Error(err, "Error building tools") - return err - } - - k.logger.Info("Creating users tools") - _, err = k.userToolsRes.Namespace(k.cfg.Kubernetes.Namespace).Create(ctx, definition, metav1.CreateOptions{}) - - if err != nil { - k.logger.Error(err, "Error creating user tools") - return err - } - - return nil -} - -func (k *Client) getUserToolsDefinition( - ingressAnnotations map[string]interface{}, - resName, username, usernameSlug, runtimeID, runtimeImage, runtimeTag, serviceAccountName string, - capabilities entity.Capabilities, -) (*unstructured.Unstructured, error) { - tlsConfig := map[string]interface{}{ - "enabled": k.cfg.TLS.Enabled, - } - - if k.cfg.UserToolsIngress.TLS.SecretName != nil { - tlsConfig["secretName"] = &k.cfg.UserToolsIngress.TLS.SecretName - } - - vscodeRuntime := map[string]interface{}{ - "runtimeId": runtimeID, - "image": map[string]string{ - "repository": runtimeImage, - "tag": runtimeTag, - "pullPolicy": k.cfg.UserToolsVsCodeRuntime.Image.PullPolicy, - }, - } - - spec := map[string]interface{}{ - "domain": k.cfg.BaseDomainName, - "ingress": map[string]interface{}{ - "annotations": ingressAnnotations, - "className": k.cfg.UserToolsIngress.ClassName, - }, - "username": username, - "usernameSlug": usernameSlug, - "storage": map[string]string{ - "size": k.cfg.Storage.Size, - "className": k.cfg.Storage.ClassName, - }, - "sharedVolume": map[string]string{ - "name": k.cfg.SharedVolume.Name, - }, - "tls": tlsConfig, - "vscode": map[string]interface{}{ - "enabled": k.cfg.VSCode.Enabled, - "image": map[string]string{ - "repository": k.cfg.VSCode.Image.Repository, - "tag": k.cfg.VSCode.Image.Tag, - "pullPolicy": k.cfg.VSCode.Image.PullPolicy, - }, - }, - "repoCloner": map[string]interface{}{ - "image": map[string]string{ - "repository": k.cfg.RepoCloner.Image.Repository, - "tag": k.cfg.RepoCloner.Image.Tag, - "pullPolicy": k.cfg.RepoCloner.Image.PullPolicy, - }, - "mongodbURI": k.cfg.MongoDB.URI, - }, - "oauth2Proxy": map[string]interface{}{ - "image": map[string]string{ - "repository": k.cfg.UserToolsOAuth2Proxy.Image.Repository, - "tag": k.cfg.UserToolsOAuth2Proxy.Image.Tag, - "pullPolicy": k.cfg.UserToolsOAuth2Proxy.Image.PullPolicy, - }, - }, - "kubeconfig": map[string]interface{}{ - "enabled": k.cfg.UserToolsKubeconfig.Enabled, - "externalServerUrl": k.cfg.UserToolsKubeconfig.ExternalServerURL, - }, - "serviceAccountName": serviceAccountName, - } - - err := k.loadCapabilites(spec, vscodeRuntime, capabilities) - if err != nil { - return nil, err - } - - spec["vscodeRuntime"] = vscodeRuntime - - definition := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "kind": "UserTools", - "apiVersion": userToolsAPIVersion, - "metadata": map[string]interface{}{ - "name": resName, - "namespace": k.cfg.Kubernetes.Namespace, - "labels": map[string]interface{}{ - "app": resName, - }, - }, - "spec": spec, - }, - } - - return definition, nil -} - -func (k *Client) loadCapabilites( - spec map[string]interface{}, - vscodeRuntime map[string]interface{}, - capabilities entity.Capabilities, -) error { - if capabilities.ID != "" { - if err := capabilities.Validate(); err != nil { - return err - } - - if !capabilities.IsNodeSelectorsEmpty() { - spec["nodeSelector"] = capabilities.GetNodeSelectors() - } - - if !capabilities.IsTolerationsEmpty() { - spec["tolerations"] = capabilities.GetTolerations() - } - - if !capabilities.IsAffinitiesEmpty() { - spec["affinity"] = capabilities.GetAffinities() - } - - vscodeRuntime["capabilityId"] = capabilities.ID - } - - return nil -} - // Returns a watcher for the UserTools. func (k *Client) createUserToolsWatcher(ctx context.Context, resName string) (watch.Interface, error) { labelSelector := k.userToolsPODLabelSelector(resName) diff --git a/app/api/infrastructure/k8s/usertools_test.go b/app/api/infrastructure/k8s/usertools_test.go new file mode 100644 index 000000000..878cbb9ab --- /dev/null +++ b/app/api/infrastructure/k8s/usertools_test.go @@ -0,0 +1,403 @@ +//go:build integration + +package k8s_test + +import ( + "context" + "time" + + "github.com/konstellation-io/kdl-server/app/api/entity" + "github.com/konstellation-io/kdl-server/app/api/infrastructure/k8s" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + username = "test.username" + runtimeID = "test-runtime-id" + runtimeImage = "test-runtime-image" + runtimeTag = "test-runtime-tag" + configMapKdlUserToolTemplateName = "kdl-server-user-tools-template" +) + +var data = k8s.UserToolsData{ + RuntimeID: runtimeID, + RuntimeImage: runtimeImage, + RuntimeTag: runtimeTag, +} +var dataWithCapabilities = k8s.UserToolsData{ + RuntimeID: runtimeID, + RuntimeImage: runtimeImage, + RuntimeTag: runtimeTag, + Capabilities: entity.Capabilities{ + ID: "test-capability-id", + Name: "test-capability-name", + Default: false, + NodeSelectors: map[string]string{"key": "value"}, + Tolerations: []map[string]interface{}{ + { + "key": "key1", + "operator": "Equal", + "value": "value1", + "effect": "NoExecute", + "tolerationSeconds": 100, + }, + }, + Affinities: map[string]interface{}{"key": "value"}, + }, +} + +func (s *testSuite) TestCreateUserToolsCR_and_DeleteUserToolsCR() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: + image: + repository: my-demo-repository + tag: my-demo-tag + nodeSelector: {} + tolerations: [] + affinity: {} + podLabels: + runtimeId: my-demo-runtime-id + capabilitiesId: my-demo-capabilities-id +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + // create go routine to cancel the context in 5 seconds. Risk of flaky test + ctx, cancelCreateUserToolCR := context.WithCancel(context.Background()) + go func() { + <-time.After(5 * time.Second) + cancelCreateUserToolCR() + }() + + err = s.Client.CreateUserToolsCR(ctx, username, dataWithCapabilities) + s.Require().NoError(err) + + // Delete the CR + // create go routine to cancel the context in 5 seconds. Risk of flaky test + ctx, cancelDeleteUserToolsCR := context.WithCancel(context.Background()) + go func() { + <-time.After(5 * time.Second) + cancelDeleteUserToolsCR() + }() + + err = s.Client.DeleteUserToolsCR(ctx, username) + s.Require().NoError(err) +} + +func (s *testSuite) TestCreateUserToolsCR_NoConfigMap() { + err := s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_ConfigMapWithoutTemplate() { + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutMetadata() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutMetadataLabels() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + name: my-demo-name + namespace: my-demo-namespace +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutSpec() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutVscodeRuntime() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutVscodeRuntimeImage() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: {} +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutSpecNodeSelector() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: + image: + repository: my-demo-repository + tag: my-demo-tag +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, dataWithCapabilities) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutSpecTolerations() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: + image: + repository: my-demo-repository + tag: my-demo-tag + nodeSelector: {} +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, dataWithCapabilities) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutAffinity() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: + image: + repository: my-demo-repository + tag: my-demo-tag + nodeSelector: {} + tolerations: [] +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, dataWithCapabilities) + s.Require().Error(err) +} + +func (s *testSuite) TestCreateUserToolsCR_TemplateWithoutSpecPodLabels() { + yamlContent := ` +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + labels: + app: kdl + name: my-demo-name + namespace: my-demo-namespace +spec: + username: my-demo-username + usernameSlug: my-demo-username-slug + vscodeRuntime: + image: + repository: my-demo-repository + tag: my-demo-tag + nodeSelector: {} + tolerations: [] + affinity: {} +` + _, err := s.Clientset.CoreV1().ConfigMaps(namespace).Create( + context.Background(), &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapKdlUserToolTemplateName, + }, + Data: map[string]string{ + "template": yamlContent, + }, + }, + metav1.CreateOptions{}, + ) + s.Require().NoError(err) + + err = s.Client.CreateUserToolsCR(context.Background(), username, data) + s.Require().Error(err) +} diff --git a/app/api/usecase/user/interactor.go b/app/api/usecase/user/interactor.go index 7b9284f15..bbc1749a4 100644 --- a/app/api/usecase/user/interactor.go +++ b/app/api/usecase/user/interactor.go @@ -178,7 +178,7 @@ func (i *Interactor) StartTools(ctx context.Context, email string, runtimeID, ca } } - var rID, rImage, rTag string + var data = k8s.UserToolsData{} if runtimeID != nil { r, err := i.repoRuntimes.Get(ctx, *runtimeID) @@ -186,28 +186,26 @@ func (i *Interactor) StartTools(ctx context.Context, email string, runtimeID, ca return entity.User{}, err } - rID = r.ID - rImage = r.DockerImage - rTag = r.DockerTag - i.logger.Info("Runtime with docker image", "runtimeId", rID, "image", rImage, "tag", rTag) + data.RuntimeID = r.ID + data.RuntimeImage = r.DockerImage + data.RuntimeTag = r.DockerTag + i.logger.Info("Runtime with docker image", "runtimeId", r.ID, "image", r.DockerImage, "tag", r.DockerTag) } else { - rID = "default" - rImage = i.cfg.UserToolsVsCodeRuntime.Image.Repository - rTag = i.cfg.UserToolsVsCodeRuntime.Image.Tag - i.logger.Info("Using default runtime image", "image", rImage, "tag", rTag) + i.logger.Info("No runtime ID provided, using default runtime values") } - retrievedCapabilities := entity.Capabilities{} if capabilitiesID != nil { - retrievedCapabilities, err = i.repoCapabilities.Get(ctx, *capabilitiesID) + data.Capabilities, err = i.repoCapabilities.Get(ctx, *capabilitiesID) if err != nil { return entity.User{}, err } + } else { + i.logger.Info("No capabilities ID provided, using default capabilities values") } i.logger.Info("Creating user tools for user", "email", email) - err = i.k8sClient.CreateUserToolsCR(ctx, user.Username, rID, rImage, rTag, retrievedCapabilities) + err = i.k8sClient.CreateUserToolsCR(ctx, user.Username, data) if err != nil { return entity.User{}, err } @@ -249,7 +247,7 @@ func (i *Interactor) AreToolsRunning(ctx context.Context, username string) (bool // IsKubeconfigActive checks if the kubeconfig is active. func (i *Interactor) IsKubeconfigActive() bool { - return i.cfg.UserToolsKubeconfig.Enabled + return i.cfg.Kubeconfig.Enabled } // FindByIDs retrieves the users for the given identifiers. diff --git a/app/api/usecase/user/interactor_test.go b/app/api/usecase/user/interactor_test.go index d0d48787f..9e136580c 100644 --- a/app/api/usecase/user/interactor_test.go +++ b/app/api/usecase/user/interactor_test.go @@ -45,7 +45,7 @@ type userMocks struct { cfg config.Config } -func newUserSuite(t *testing.T, cfg *config.Config) *userSuite { +func newUserSuite(t *testing.T) *userSuite { ctrl := gomock.NewController(t) repo := user.NewMockRepository(ctrl) repoRuntimes := runtime.NewMockRepository(ctrl) @@ -59,9 +59,7 @@ func newUserSuite(t *testing.T, cfg *config.Config) *userSuite { logger := zapr.NewLogger(zapLog) - if cfg == nil { - cfg = &config.Config{} - } + cfg := &config.Config{} interactor := user.NewInteractor(logger, *cfg, repo, repoRuntimes, repoCapabilities, sshGenerator, clockMock, k8sClientMock) @@ -83,7 +81,7 @@ func newUserSuite(t *testing.T, cfg *config.Config) *userSuite { } func TestInteractor_Create(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -141,7 +139,7 @@ func TestInteractor_Create(t *testing.T) { } func TestInteractor_Create_UserDuplEmail(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -162,7 +160,7 @@ func TestInteractor_Create_UserDuplEmail(t *testing.T) { } func TestInteractor_Create_UserDuplUsername(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -182,7 +180,7 @@ func TestInteractor_Create_UserDuplUsername(t *testing.T) { } func TestInteractor_Create_UserDuplSub(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -204,7 +202,7 @@ func TestInteractor_Create_UserDuplSub(t *testing.T) { } func TestInteractor_AreToolsRunning(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -223,7 +221,7 @@ func TestInteractor_AreToolsRunning(t *testing.T) { } func TestInteractor_StopTools(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -246,7 +244,7 @@ func TestInteractor_StopTools(t *testing.T) { } func TestInteractor_StopTools_Err(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -269,7 +267,7 @@ func TestInteractor_StopTools_Err(t *testing.T) { } func TestInteractor_StartTools(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -292,6 +290,13 @@ func TestInteractor_StartTools(t *testing.T) { runtimeID := "12345" + data := k8s.UserToolsData{ + RuntimeID: runtimeID, + RuntimeImage: runtimeImage, + RuntimeTag: runtimeTag, + Capabilities: capability, + } + ctx := context.Background() expectedUser := entity.User{Username: username, Email: email} expectedRuntime := entity.Runtime{ID: runtimeID, DockerImage: runtimeImage, DockerTag: runtimeTag} @@ -300,7 +305,7 @@ func TestInteractor_StartTools(t *testing.T) { s.mocks.runtimeRepo.EXPECT().Get(ctx, runtimeID).Return(expectedRuntime, nil) s.mocks.capabilitiesRepo.EXPECT().Get(ctx, capability.ID).Return(capability, nil) s.mocks.k8sClientMock.EXPECT().IsUserToolPODRunning(ctx, username).Return(toolsRunning, nil) - s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, runtimeID, runtimeImage, runtimeTag, capability).Return(nil) + s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, data).Return(nil) returnedUser, err := s.interactor.StartTools(ctx, email, &runtimeID, &capability.ID) @@ -310,18 +315,13 @@ func TestInteractor_StartTools(t *testing.T) { func TestInteractor_StartTools_DefaultRuntime(t *testing.T) { // GIVEN there is a default image defined for the Runtime - cfg := config.Config{} - cfg.UserToolsVsCodeRuntime.Image.Repository = "defaultImage" - cfg.UserToolsVsCodeRuntime.Image.Tag = "3.9" - - s := newUserSuite(t, &cfg) + s := newUserSuite(t) defer s.ctrl.Finish() const ( username = "john" email = "john@doe.com" toolsRunning = false - runtimeID = "default" ) capability := entity.Capabilities{ @@ -334,6 +334,10 @@ func TestInteractor_StartTools_DefaultRuntime(t *testing.T) { Affinities: map[string]interface{}{}, } + data := k8s.UserToolsData{ + Capabilities: capability, + } + ctx := context.Background() expectedUser := entity.User{Username: username, Email: email} @@ -344,8 +348,7 @@ func TestInteractor_StartTools_DefaultRuntime(t *testing.T) { s.mocks.capabilitiesRepo.EXPECT().Get(ctx, capability.ID).Return(capability, nil) // AND the CR creation does not return any error - s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, runtimeID, - cfg.UserToolsVsCodeRuntime.Image.Repository, cfg.UserToolsVsCodeRuntime.Image.Tag, capability).Return(nil) + s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, data).Return(nil) // WHEN the tools are started returnedUser, err := s.interactor.StartTools(ctx, email, nil, &capability.ID) @@ -363,7 +366,7 @@ func TestInteractor_StartTools_DefaultRuntime(t *testing.T) { func TestInteractor_StartTools_Replace(t *testing.T) { // GIVEN there is a valid context - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -388,6 +391,13 @@ func TestInteractor_StartTools_Replace(t *testing.T) { Affinities: map[string]interface{}{}, } + data := k8s.UserToolsData{ + RuntimeID: runtimeID, + RuntimeImage: dockerImage, + RuntimeTag: dockerTag, + Capabilities: capability, + } + ctx := context.Background() // AND the user is the in repo @@ -401,7 +411,7 @@ func TestInteractor_StartTools_Replace(t *testing.T) { s.mocks.capabilitiesRepo.EXPECT().Get(ctx, capability.ID).Return(capability, nil) // AND the CR creation does not return any error - s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, runtimeID, dockerImage, dockerTag, capability).Return(nil) + s.mocks.k8sClientMock.EXPECT().CreateUserToolsCR(ctx, username, data).Return(nil) // WHEN the tools are started returnedUser, err := s.interactor.StartTools(ctx, email, &runtimeID, &capability.ID) @@ -413,7 +423,7 @@ func TestInteractor_StartTools_Replace(t *testing.T) { } //nolint:wsl // we want the test to end with the comment to respect the AND orders func TestInteractor_FindAll(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() ctx := context.Background() @@ -428,7 +438,7 @@ func TestInteractor_FindAll(t *testing.T) { } func TestInteractor_FindAll_Err(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() var emptyUsers []entity.User @@ -445,7 +455,7 @@ func TestInteractor_FindAll_Err(t *testing.T) { } func TestInteractor_GetByEmail(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const email = "john@doe.com" @@ -462,7 +472,7 @@ func TestInteractor_GetByEmail(t *testing.T) { } func TestInteractor_GetByEmail_Err(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const email = "john@doe.com" @@ -480,7 +490,7 @@ func TestInteractor_GetByEmail_Err(t *testing.T) { } func TestInteractor_FindByIDs(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() ctx := context.Background() @@ -497,7 +507,7 @@ func TestInteractor_FindByIDs(t *testing.T) { } func TestInteractor_GetByID(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() ctx := context.Background() @@ -514,7 +524,7 @@ func TestInteractor_GetByID(t *testing.T) { } func TestInteractor_RegenerateSSHKeys(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -557,7 +567,7 @@ func TestInteractor_RegenerateSSHKeys(t *testing.T) { } func TestInteractor_RegenerateSSHKeys_UserToolsRunning(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -596,7 +606,7 @@ func TestInteractor_RegenerateSSHKeys_UserToolsRunning(t *testing.T) { } func TestInteractor_UpdateAccessLevel(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -628,7 +638,7 @@ func TestInteractor_UpdateAccessLevel(t *testing.T) { } func TestInteractor_UpdateSub(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -659,7 +669,7 @@ func TestInteractor_UpdateSub(t *testing.T) { } func TestInteractor_UpdateSub_UpdateError(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -689,7 +699,7 @@ func TestInteractor_UpdateSub_UpdateError(t *testing.T) { } func TestInteractor_UpdateSub_DuplicatedUserSub(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -720,7 +730,7 @@ func TestInteractor_UpdateSub_DuplicatedUserSub(t *testing.T) { } func TestInteractor_GetKubeconfig(t *testing.T) { - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( @@ -749,7 +759,7 @@ func TestInteractor_SynchronizeServiceAccountsForUsers(t *testing.T) { // AND k8client.CreateUserServiceAccount is called two times // AND k8client.DeleteUserServiceAccount is called one time // AND there are no errors - s := newUserSuite(t, nil) + s := newUserSuite(t) defer s.ctrl.Finish() const ( diff --git a/filebrowser/Dockerfile b/filebrowser/Dockerfile new file mode 100644 index 000000000..d3ecdd472 --- /dev/null +++ b/filebrowser/Dockerfile @@ -0,0 +1,31 @@ +ARG BASE_S3FUSE_IMAGE_VERSION=1.94 +ARG BASE_FILEBROWSER_IMAGE_VERSION=v2 + +FROM efrecon/s3fs:${BASE_S3FUSE_IMAGE_VERSION} AS s3fs +FROM filebrowser/filebrowser:${BASE_FILEBROWSER_IMAGE_VERSION} + +COPY --from=s3fs /usr/bin/s3fs /usr/bin/s3fs +COPY --from=s3fs /usr/local/bin/*.sh /usr/local/bin/ +COPY --from=s3fs /etc/fuse.conf /etc/fuse.conf + +# s3fs dependencies +RUN apk add --no-cache \ + fuse \ + libxml2 \ + libcurl \ + libgcc \ + libstdc++ \ + tini && \ + mkdir -p /srv && \ + # Create non-root user + addgroup -g 1000 filebrowser && \ + adduser -D -u 1000 -G filebrowser filebrowser && \ + chown -R filebrowser:filebrowser /srv + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +VOLUME ["/srv"] +EXPOSE 9696 + +ENTRYPOINT ["tini", "-g", "--", "/entrypoint.sh"] diff --git a/filebrowser/README.md b/filebrowser/README.md new file mode 100644 index 000000000..0982c89db --- /dev/null +++ b/filebrowser/README.md @@ -0,0 +1,78 @@ +# Filebrowser with S3Fuse + +Docker image combining `Filebrowser` web interface with `S3Fuse` mount capabilities for S3-compatible storage, providing a seamless way to browse and manage files both locally and in S3 buckets. + +## Security Features + +* Non-root user (`filebrowser`) execution with configurable UID/GID (default `1000:1000`) +* Proper permission handling +* Tini as init system for proper process management + +## Configuration + +### Build Arguments + +| Variable | Description | Default | +|--------------------------|----------------------------|---------| +| `BASE_FILEBROWSER_IMAGE` | Filebrowser base image tag | `v2` | +| `BASE_S3FUSE_IMAGE` | S3Fuse base image tag | `1.94` | + +### Environment Variables + +| Variable | Description | Required | +|----------------------------|---------------------------------|----------| +| `AWS_S3_ACCESS_KEY_ID` | AWS/S3 access key | `Yes` | +| `AWS_S3_BUCKET` | S3 bucket name to mount | `Yes` | +| `AWS_S3_MOUNT` | Mount point inside container | `No` | +| `AWS_S3_SECRET_ACCESS_KEY` | AWS/S3 secret key | `Yes` | +| `AWS_S3_URL` | S3-compatible endpoint URL | `Yes` | +| `S3FS_ARGS` | Additional S3Fuse mount options | `No` | + +## Storage + +* Web interface files: `/srv` +* S3 bucket mount: configurable via `AWS_S3_MOUNT` (default: `/srv`) +* Filebrowser database: `/database.db` + +## Local Deployment + +Basic usage: + +```bash +docker run -p 9696:9696 \ + -e "AWS_S3_ACCESS_KEY_ID=user" \ + -e "AWS_S3_BUCKET=my-bucket" \ + -e "AWS_S3_SECRET_ACCESS_KEY=pass" \ + -e "FB_ADDRESS="0.0.0.0" \ + -e "FB_DATABASE=/database.db \ + -e "FB_LOG=stdout \ + -e "FB_ROOT=/srv \ + --device /dev/fuse \ + --cap-add SYS_ADMIN \ + --security-opt apparmor:unconfined \ + konstellation/kdl-filebrowser:latest +``` + +With custom configuration: + +```bash +docker run -p 9696:9696 \ + --user 1000:1000 \ + -e "AWS_S3_ACCESS_KEY_ID=user" \ + -e "AWS_S3_BUCKET=my-bucket" \ + -e "AWS_S3_MOUNT=/srv/data" \ + -e "AWS_S3_SECRET_ACCESS_KEY=pass" \ + -e "AWS_S3_URL=http://minio:9000" \ + -e "FB_ADDRESS="0.0.0.0" \ + -e "FB_DATABASE=/database.db \ + -e "FB_LOG=stdout \ + -e "FB_ROOT=/srv \ + -e "S3FS_ARGS=allow_other,use_path_request_style" \ + -v /path/to/config:/srv \ + --device /dev/fuse \ + --cap-add SYS_ADMIN \ + --security-opt apparmor:unconfined \ + konstellation/kdl-filebrowser:latest +``` + +Access the web interface at diff --git a/filebrowser/entrypoint.sh b/filebrowser/entrypoint.sh new file mode 100644 index 000000000..29258a951 --- /dev/null +++ b/filebrowser/entrypoint.sh @@ -0,0 +1,28 @@ +# Mount S3 bucket if configured +if [ -n "$AWS_S3_BUCKET" ]; then + echo "Mounting S3 bucket..." + + # Set up authentication + if [ -n "$AWS_S3_ACCESS_KEY_ID" ] && [ -n "$AWS_S3_SECRET_ACCESS_KEY" ]; then + echo "$AWS_S3_ACCESS_KEY_ID:$AWS_S3_SECRET_ACCESS_KEY" > /etc/passwd-s3fs + chmod 600 /etc/passwd-s3fs + fi + + # Mount the bucket + s3fs "$AWS_S3_BUCKET" "$AWS_S3_MOUNT" \ + -o passwd_file=/etc/passwd-s3fs \ + -o url="$AWS_S3_URL" \ + -o allow_other \ + $S3FS_ARGS + + # Wait for mount to be ready + while ! mountpoint -q "$AWS_S3_MOUNT"; do + echo "Waiting for S3 mount to be ready..." + sleep 1 + done + echo "S3 mount completed" +fi + +# Start filebrowser +echo "Starting filebrowser..." +exec /filebrowser diff --git a/filebrowser/package.json b/filebrowser/package.json new file mode 100644 index 000000000..35b465a53 --- /dev/null +++ b/filebrowser/package.json @@ -0,0 +1,79 @@ +{ + "name": "filebrowser", + "version": "1.0.0", + "private": true, + "release": { + "tagFormat": "filebrowser-v${version}", + "extends": "semantic-release-monorepo", + "branches": [ + "main", + { + "channel": "default", + "name": "release/*", + "prerelease": "rc" + }, + { + "channel": "default", + "name": "hotfix/+([0-9])?(.{+([0-9]),x}).x", + "prerelease": false, + "range": "${name.replace(/^hotfix\\//g, '')}" + } + ], + "plugins": [ + "@semantic-release/commit-analyzer", + [ + "@semantic-release/git", + { + "assets": [ + "**/package.json" + ], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + } + ], + [ + "@semantic-release/github", + { + "failComment": false, + "published": true, + "successComment": false + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { + "type": "chore", + "section": "Miscellaneous Chores" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + }, + { + "type": "docs", + "section": "Documentation", + "hidden": true + }, + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "refactor", + "section": "Code Refactoring" + } + ] + } + } + ] + ] + } +} diff --git a/go.work.sum b/go.work.sum index 30636918f..258ac8080 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,9 +1,12 @@ cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -11,6 +14,7 @@ github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -18,6 +22,9 @@ github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwys github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= @@ -43,18 +50,30 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= @@ -73,9 +92,13 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/intel/goresctrl v0.3.0/go.mod h1:fdz3mD85cmP9sHD8JUlrNWAxvwM86CrbmVXltEKd7zk= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= github.com/matryer/moq v0.4.0/go.mod h1:kUfalaLk7TcyXhrhonBYQ2Ewun63+/xGbZ7/MzzzC4Y= @@ -95,12 +118,15 @@ github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= @@ -116,10 +142,14 @@ github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3V github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= @@ -130,6 +160,8 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -152,23 +184,52 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= @@ -182,6 +243,8 @@ google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= k8s.io/apiserver v0.32.0/go.mod h1:HFh+dM1/BE/Hm4bS4nTXHVfN6Z6tFIZPi649n83b4Ag= diff --git a/hack/scripts/helmfile/values/kdl-local/values.yaml.gotmpl b/hack/scripts/helmfile/values/kdl-local/values.yaml.gotmpl index 3d841f9e7..813e95e4b 100644 --- a/hack/scripts/helmfile/values/kdl-local/values.yaml.gotmpl +++ b/hack/scripts/helmfile/values/kdl-local/values.yaml.gotmpl @@ -15,6 +15,8 @@ image: env: KDL_SERVER_MONGODB_URI: "mongodb://{{ .Values.mongodb_user }}:{{ .Values.mongodb_password }}@mongodb-svc.mongodb:27017/{{ .Values.mongodb_user }}?authSource={{ .Values.mongodb_user }}&authMechanism=SCRAM-SHA-256" KDL_SERVER_PORT: "8080" + KUBECONFIG_DOWNLOAD_ENABLED: {{ requiredEnv "KUBECONFIG_ENABLED" }} + KUBECONFIG_EXTERNAL_SERVER_URL: {{ env "EXTERNAL_SERVER_URL" | quote }} MINIO_ACCESS_KEY: "{{ .Values.minio_access_key }}" MINIO_ENDPOINT: "minio:9000" MINIO_SECRET_KEY: "{{ .Values.minio_secret_key }}" @@ -122,11 +124,11 @@ minio: mode: standalone ingress: - enabled: true + enabled: false ingressClassName: public annotations: cert-manager.io/cluster-issuer: selfsigned-clusterissuer - nginx.ingress.kubernetes.io/proxy-body-size: "1000000m" + nginx.ingress.kubernetes.io/proxy-body-size: "4096m" path: / hosts: - minio.{{ requiredEnv "DOMAIN" }} @@ -140,7 +142,7 @@ minio: ingressClassName: public annotations: cert-manager.io/cluster-issuer: selfsigned-clusterissuer - nginx.ingress.kubernetes.io/proxy-body-size: "1000000m" + nginx.ingress.kubernetes.io/proxy-body-size: "4096m" path: / hosts: - minio-console.{{ requiredEnv "DOMAIN" }} @@ -256,25 +258,24 @@ projectOperator: image: repository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-project-operator - tag: latest pullPolicy: Always + tag: latest templateCustomResource: | apiVersion: kdl.konstellation.io/v1 kind: KDLProject metadata: name: kdlproject-to-be-replaced - namespace: kdl-to-be-replaced + namespace: kdlproject-to-be-replaced spec: domain: {{ requiredEnv "DOMAIN" | quote }} projectId: kdlproject-id-to-be-replaced mlflow: image: - repository: konstellation/kdl-mlflow + repository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-mlflow pullPolicy: IfNotPresent - tag: "0.14.18" + tag: latest - # Ingress configuration ingress: enabled: true tls: @@ -282,9 +283,8 @@ projectOperator: className: public annotations: cert-manager.io/cluster-issuer: selfsigned-clusterissuer - nginx.ingress.kubernetes.io/proxy-body-size: "50m" + nginx.ingress.kubernetes.io/proxy-body-size: "4096m" - # Persistent storage configuration persistentVolume: enabled: true size: "1Gi" @@ -292,32 +292,66 @@ projectOperator: - ReadWriteOnce storageClass: {{ requiredEnv "STORAGE_CLASS_NAME" | quote }} - # Environment variables env: + AWS_ACCESS_KEY_ID: "{{ .Values.minio_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ .Values.minio_secret_key }}" MLFLOW_S3_ENDPOINT_URL: "http://minio.kdl:9000" - MLFLOW_TRACKING_URI: "sqlite3:///database.db" - ARTIFACTS_BUCKET: "nanana" - AWS_ACCESS_KEY_ID: "minio" - AWS_SECRET_ACCESS_KEY: "minio123" + MLFLOW_TRACKING_URI: "sqlite:///database.db" filebrowser: image: - repository: filebrowser/filebrowser + repository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-filebrowser pullPolicy: IfNotPresent - tag: "v2" + tag: latest - # Volume configuration - volumes: - - name: received-data - persistentVolumeClaim: - claimName: shared-volume + podSecurityContext: + fsGroup: 1000 + + securityContext: + privileged: true + capabilities: + add: + - SYS_ADMIN env: - FB_ADDRESS: 0.0.0.0 - FB_PORT: 9696 + AWS_S3_ACCESS_KEY_ID: "minio" + AWS_S3_MOUNT: "/srv" + AWS_S3_SECRET_ACCESS_KEY: "minio123" + AWS_S3_URL: "http://minio:9000" + FB_ADDRESS: "0.0.0.0" FB_DATABASE: /database.db FB_LOG: stdout FB_ROOT: /srv + S3FS_ARGS: >- + -o use_path_request_style + -o use_cache=/cache + -o ensure_diskfree=2048 + -o max_stat_cache_size=100000 + -o stat_cache_expire=300 + -o enable_noobj_cache + -o dbglevel=warn + -o multipart_size=52 + -o parallel_count=32 + -o max_dirty_data=512 + -o multireq_max=30 + -o complement_stat + -o notsup_compat_dir + -o enable_content_md5 + -o ro + + volumes: + - name: cache-volume + emptyDir: {} + - name: fuse-device + hostPath: + path: /dev/fuse + type: CharDevice + + volumeMounts: + - name: cache-volume + mountPath: /cache + - name: fuse-device + mountPath: /dev/fuse sharedVolume: enabled: true @@ -336,23 +370,52 @@ userToolsOperator: storage: storageClassName: {{ requiredEnv "STORAGE_CLASS_NAME" | quote }} - repoCloner: - image: - repository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-repo-cloner - tag: latest - pullPolicy: Always + templateCustomResource: | + apiVersion: kdl.konstellation.io/v1 + kind: KDLUserTools + metadata: + name: kdlusertools-to-be-replaced + namespace: kdlusertools-to-be-replaced + spec: + username: replaced-by-kdl-api + usernameSlug: replaced-by-kdl-api - vscode: - enabled: false + sharedVolume: + enabled: false - image: - epository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-vscode - tag: latest - pullPolicy: Always + podLabels: {} - ingress: - className: "public" + persistentVolume: + enabled: true + size: "1Gi" + accessModes: + - ReadWriteOnce + storageClass: {{ requiredEnv "STORAGE_CLASS_NAME" | quote }} + + kubeconfig: + enabled: {{ requiredEnv "KUBECONFIG_ENABLED" }} + externalServerUrl: {{ env "EXTERNAL_SERVER_URL" | quote }} + + repoCloner: + image: + repository: {{ requiredEnv "IMAGE_REGISTRY" }}/konstellation/kdl-repo-cloner + pullPolicy: IfNotPresent + tag: "latest" + + env: + KDL_SERVER_MONGODB_URI: "mongodb://{{ .Values.mongodb_user }}:{{ .Values.mongodb_password }}@mongodb-svc.mongodb:27017/{{ .Values.mongodb_user }}?authSource={{ .Values.mongodb_user }}&authMechanism=SCRAM-SHA-256" + + vscodeRuntime: + image: + repository: konstellation/kdl-py + pullPolicy: IfNotPresent + tag: "3.9" + + env: + AWS_ACCESS_KEY: "{{ .Values.minio_access_key }}" + AWS_SECRET_KEY: "{{ .Values.minio_secret_key }}" + MINIO_ENDPOINT: "minio:9000" - kubeconfig: - enabled: {{ requiredEnv "KUBECONFIG_ENABLED" }} - externalServerUrl: {{ env "EXTERNAL_SERVER_URL" | quote }} + nodeSelector: {} + tolerations: [] + affinity: {} diff --git a/hack/scripts/kdlctl/cmd_build.sh b/hack/scripts/kdlctl/cmd_build.sh index 0872c24b1..f0f2153c7 100644 --- a/hack/scripts/kdlctl/cmd_build.sh +++ b/hack/scripts/kdlctl/cmd_build.sh @@ -19,6 +19,7 @@ build_docker_images() { build_user_tools_operator build_vscode build_repo_cloner + build_filebrowser build_mlflow build_kg } @@ -43,6 +44,10 @@ build_repo_cloner() { build_image kdl-repo-cloner repo-cloner } +build_filebrowser() { + build_image kdl-filebrowser filebrowser +} + build_mlflow() { build_image kdl-mlflow mlflow } diff --git a/project-operator/Dockerfile b/project-operator/Dockerfile index 8545e2003..eb03aa1cc 100644 --- a/project-operator/Dockerfile +++ b/project-operator/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/operator-framework/helm-operator:v1.37 +FROM quay.io/operator-framework/helm-operator:v1.38 LABEL maintainer="Intelygenz - Konstellation Team" diff --git a/project-operator/helm-charts/kdl-project/Chart.yaml b/project-operator/helm-charts/kdl-project/Chart.yaml index f043065b2..97a54200a 100644 --- a/project-operator/helm-charts/kdl-project/Chart.yaml +++ b/project-operator/helm-charts/kdl-project/Chart.yaml @@ -3,7 +3,7 @@ type: application name: kdl-project description: A Helm chart to deploy KDL projects version: 1.0.0 -appVersion: 1.37.0 +appVersion: 1.38.0 sources: - https://github.com/konstellation-io/kdl-server home: https://www.konstellation.io diff --git a/project-operator/helm-charts/kdl-project/README.md b/project-operator/helm-charts/kdl-project/README.md index f14c68f0d..459e78987 100644 --- a/project-operator/helm-charts/kdl-project/README.md +++ b/project-operator/helm-charts/kdl-project/README.md @@ -90,7 +90,7 @@ helm template test . -f ci/ci-values.yaml | Key | Type | Default | Description | |-----|------|---------|-------------| | domain | string | `"kdl.local"` | String to set domain to deploy | -| filebrowser | object | `{"affinity":{},"args":["-c","/entrypoint.sh"],"autoscaling":{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80},"command":["/bin/sh"],"enabled":true,"env":{"FB_ADDRESS":"0.0.0.0","FB_DATABASE":"/database.db","FB_LOG":"stdout","FB_ROOT":"/srv"},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"extraContainers":[],"image":{"pullPolicy":"IfNotPresent","repository":"filebrowser/filebrowser","tag":"v2"},"imagePullSecrets":[],"initContainers":[],"lifecycle":{},"livenessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"livenessProbeCustom":{},"networkPolicy":{"egress":[],"enabled":false,"ingress":[],"policyTypes":[]},"nodeSelector":{},"podAnnotations":{},"podDisruptionBudget":{"enabled":false,"maxUnavailable":1,"minAvailable":null},"podLabels":{},"podSecurityContext":{},"readinessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"readinessProbeCustom":{},"replicaCount":1,"resources":{},"secrets":[],"securityContext":{},"service":{"port":9696,"type":"ClusterIP"},"serviceAccount":{"annotations":{},"automount":true,"create":true,"name":""},"startupProbe":{"enabled":false,"failureThreshold":30,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"startupProbeCustom":{},"terminationGracePeriodSeconds":30,"tolerations":[],"topologySpreadConstraints":[],"volumeMounts":[],"volumes":[]}` | Filebrowser sevice
Ref: https://filebrowser.org | +| filebrowser | object | `{"affinity":{},"args":["-c","/entrypoint.sh"],"autoscaling":{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80},"command":["/bin/sh"],"enabled":true,"env":{"FB_ADDRESS":"0.0.0.0","FB_DATABASE":"/database.db","FB_LOG":"stdout","FB_ROOT":"/srv"},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"extraContainers":[],"image":{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-filebrowser","tag":"latest"},"imagePullSecrets":[],"initContainers":[],"lifecycle":{},"livenessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"livenessProbeCustom":{},"networkPolicy":{"egress":[],"enabled":false,"ingress":[],"policyTypes":[]},"nodeSelector":{},"podAnnotations":{},"podDisruptionBudget":{"enabled":false,"maxUnavailable":1,"minAvailable":null},"podLabels":{},"podSecurityContext":{},"readinessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"readinessProbeCustom":{},"replicaCount":1,"resources":{},"securityContext":{},"service":{"port":9696,"type":"ClusterIP"},"serviceAccount":{"annotations":{},"automount":true,"create":true,"name":""},"startupProbe":{"enabled":false,"failureThreshold":30,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"startupProbeCustom":{},"terminationGracePeriodSeconds":30,"tolerations":[],"topologySpreadConstraints":[],"volumeMounts":[],"volumes":[]}` | Filebrowser sevice
Ref: https://filebrowser.org | | filebrowser.affinity | object | `{}` | Affinity for pod assignment
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity | | filebrowser.args | list | `["-c","/entrypoint.sh"]` | Configure args
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | | filebrowser.autoscaling | object | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Autoscaling with CPU or memory utilization percentage
Ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ | @@ -101,7 +101,7 @@ helm template test . -f ci/ci-values.yaml | filebrowser.envFromFiles | list | `[]` | Load all variables from files
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables | | filebrowser.envFromSecrets | object | `{}` | Variables from secrets | | filebrowser.extraContainers | list | `[]` | Configure extra containers | -| filebrowser.image | object | `{"pullPolicy":"IfNotPresent","repository":"filebrowser/filebrowser","tag":"v2"}` | Image registry The image configuration for the base service | +| filebrowser.image | object | `{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-filebrowser","tag":"latest"}` | Image registry The image configuration for the base service | | filebrowser.imagePullSecrets | list | `[]` | Specifies the secrets to use for pulling images from private registries Leave empty if no secrets are required E.g. imagePullSecrets: - name: myRegistryKeySecretName | | filebrowser.initContainers | list | `[]` | Configure additional containers
Ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | | filebrowser.lifecycle | object | `{}` | Configure lifecycle hooks
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
Ref: https://learnk8s.io/graceful-shutdown | @@ -119,7 +119,6 @@ helm template test . -f ci/ci-values.yaml | filebrowser.readinessProbeCustom | object | `{}` | Custom readinessProbe | | filebrowser.replicaCount | int | `1` | Number of replicas Specifies the number of replicas for the service | | filebrowser.resources | object | `{}` | Resources limits and requested
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| filebrowser.secrets | list | `[]` | Secrets values to create credentials and reference by envFromSecrets Generate Secret with following name: -
Ref: https://kubernetes.io/docs/concepts/configuration/secret/ | | filebrowser.securityContext | object | `{}` | Defines privilege and access control settings for a Container
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | | filebrowser.service | object | `{"port":9696,"type":"ClusterIP"}` | Kubernetes service to expose Pod
Ref: https://kubernetes.io/docs/concepts/services-networking/service/ | | filebrowser.service.port | int | `9696` | Kubernetes Service port | @@ -133,7 +132,7 @@ helm template test . -f ci/ci-values.yaml | filebrowser.volumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition | | filebrowser.volumes | list | `[]` | Additional volumes on the output Deployment definition
Ref: https://kubernetes.io/docs/concepts/storage/volumes/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/
Ref: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#create-a-pod-that-has-access-to-the-secret-data-through-a-volume | | fullnameOverride | string | `""` | String to fully override kdl-project.fullname template | -| mlflow | object | `{"affinity":{},"args":[],"autoscaling":{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80},"command":[],"enabled":true,"env":{"MLFLOW_BACKEND_STORE_URI":"sqlite:///mlflow.db","MLFLOW_HOST":"0.0.0.0","MLFLOW_PORT":"5000"},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"extraContainers":[],"image":{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-mlflow","tag":"latest"},"imagePullSecrets":[],"ingress":{"annotations":{},"className":"","enabled":false,"hosts":[],"tls":{"enabled":false,"extraTLS":[]}},"initContainers":[],"lifecycle":{},"livenessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"livenessProbeCustom":{},"networkPolicy":{"egress":[],"enabled":false,"ingress":[],"policyTypes":[]},"nodeSelector":{},"persistentVolume":{"accessModes":["ReadWriteOnce"],"annotations":{},"enabled":true,"labels":{},"selector":{},"size":"1Gi","storageClass":"","volumeBindingMode":"","volumeName":""},"podAnnotations":{},"podDisruptionBudget":{"enabled":false,"maxUnavailable":1,"minAvailable":null},"podLabels":{},"podSecurityContext":{},"readinessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"readinessProbeCustom":{},"replicaCount":1,"resources":{},"secrets":[],"securityContext":{},"service":{"port":5000,"type":"ClusterIP"},"serviceAccount":{"annotations":{},"automount":true,"create":true,"name":""},"startupProbe":{"enabled":false,"failureThreshold":30,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"startupProbeCustom":{},"terminationGracePeriodSeconds":30,"tolerations":[],"topologySpreadConstraints":[],"volumeMounts":[],"volumes":[]}` | MLflow sevice
Ref: https://mlflow.org/docs/latest/index.html | +| mlflow | object | `{"affinity":{},"args":[],"autoscaling":{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80},"command":[],"enabled":true,"env":{"MLFLOW_BACKEND_STORE_URI":"sqlite:///mlflow.db","MLFLOW_HOST":"0.0.0.0","MLFLOW_PORT":"5000"},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"extraContainers":[],"image":{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-mlflow","tag":"latest"},"imagePullSecrets":[],"ingress":{"annotations":{},"className":"","enabled":false,"hosts":[],"tls":{"enabled":false,"extraTLS":[]}},"initContainers":[],"lifecycle":{},"livenessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"livenessProbeCustom":{},"networkPolicy":{"egress":[],"enabled":false,"ingress":[],"policyTypes":[]},"nodeSelector":{},"persistentVolume":{"accessModes":["ReadWriteOnce"],"annotations":{},"enabled":true,"labels":{},"selector":{},"size":"1Gi","storageClass":"","volumeBindingMode":"","volumeName":""},"podAnnotations":{},"podDisruptionBudget":{"enabled":false,"maxUnavailable":1,"minAvailable":null},"podLabels":{},"podSecurityContext":{},"readinessProbe":{"enabled":false,"failureThreshold":3,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"readinessProbeCustom":{},"replicaCount":1,"resources":{},"securityContext":{},"service":{"port":5000,"type":"ClusterIP"},"serviceAccount":{"annotations":{},"automount":true,"create":true,"name":""},"startupProbe":{"enabled":false,"failureThreshold":30,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"startupProbeCustom":{},"terminationGracePeriodSeconds":30,"tolerations":[],"topologySpreadConstraints":[],"volumeMounts":[],"volumes":[]}` | MLflow sevice
Ref: https://mlflow.org/docs/latest/index.html | | mlflow.affinity | object | `{}` | Affinity for pod assignment
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity | | mlflow.args | list | `[]` | Configure args
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | | mlflow.autoscaling | object | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Autoscaling with CPU or memory utilization percentage
Ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ | @@ -146,7 +145,7 @@ helm template test . -f ci/ci-values.yaml | mlflow.extraContainers | list | `[]` | Configure extra containers | | mlflow.image | object | `{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-mlflow","tag":"latest"}` | Image registry The image configuration for the base service | | mlflow.imagePullSecrets | list | `[]` | Specifies the secrets to use for pulling images from private registries Leave empty if no secrets are required E.g. imagePullSecrets: - name: myRegistryKeySecretName | -| mlflow.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"chart-example.local","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | Ingress configuration to expose app
Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ | +| mlflow.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[],"tls":{"enabled":false,"extraTLS":[]}}` | Ingress configuration to expose app
Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ | | mlflow.initContainers | list | `[]` | Configure additional containers
Ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | | mlflow.lifecycle | object | `{}` | Configure lifecycle hooks
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
Ref: https://learnk8s.io/graceful-shutdown | | mlflow.livenessProbe | object | `{"enabled":false,"failureThreshold":3,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5}` | Configure liveness checker
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes | @@ -173,7 +172,6 @@ helm template test . -f ci/ci-values.yaml | mlflow.readinessProbeCustom | object | `{}` | Custom readinessProbe | | mlflow.replicaCount | int | `1` | Number of replicas Specifies the number of replicas for the service | | mlflow.resources | object | `{}` | Resources limits and requested
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| mlflow.secrets | list | `[]` | Secrets values to create credentials and reference by envFromSecrets Generate Secret with following name: -
Ref: https://kubernetes.io/docs/concepts/configuration/secret/ | | mlflow.securityContext | object | `{}` | Defines privilege and access control settings for a Container
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | | mlflow.service | object | `{"port":5000,"type":"ClusterIP"}` | Kubernetes service to expose Pod
Ref: https://kubernetes.io/docs/concepts/services-networking/service/ | | mlflow.service.port | int | `5000` | Kubernetes Service port | diff --git a/project-operator/helm-charts/kdl-project/ci/ci-values.yaml b/project-operator/helm-charts/kdl-project/ci/ci-values.yaml index f4a5e0a69..c484bb931 100644 --- a/project-operator/helm-charts/kdl-project/ci/ci-values.yaml +++ b/project-operator/helm-charts/kdl-project/ci/ci-values.yaml @@ -22,88 +22,15 @@ filebrowser: ci.konstellation.io/tested: "true" ci.konstellation.io/version: "v1" - nodeSelector: - kubernetes.io/role: worker - node-type: application - - tolerations: - - key: "workload-type" - operator: "Equal" - value: "ci" - effect: "NoSchedule" - - key: "node-role" - operator: "Exists" - effect: "NoSchedule" - - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - - arm64 - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchLabels: - app.kubernetes.io/name: filebrowser - topologyKey: kubernetes.io/hostname - - topologySpreadConstraints: - - maxSkew: 1 - topologyKey: topology.kubernetes.io/zone - whenUnsatisfiable: DoNotSchedule - labelSelector: - matchLabels: - app.kubernetes.io/name: filebrowser - serviceAccount: create: true automount: true - annotations: - iam.gke.io/gcp-service-account: "filebrowser@my-project.iam.gserviceaccount.com" env: FB_ADDRESS: "0.0.0.0" FB_DATABASE: "/database.db" FB_LOG: "stdout" - FB_PORT: "9696" FB_ROOT: "/srv" - FB_BASEURL: "" - FB_NOAUTH: "false" - FB_USERNAME: "admin" - - envFromSecrets: - FB_PASSWORD: - name: filebrowser-credentials - key: admin-password - - secrets: - - name: filebrowser-credentials - data: - admin-password: "changeme123!" - - securityContext: - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 200m - memory: 256Mi livenessProbe: enabled: true @@ -127,23 +54,13 @@ filebrowser: path: / port: 9696 - volumes: - - name: filebrowser-data - persistentVolumeClaim: - claimName: filebrowser-data - - name: filebrowser-database - persistentVolumeClaim: - claimName: filebrowser-db - - volumeMounts: - - name: filebrowser-data - mountPath: "/srv" - - name: filebrowser-database - mountPath: "/database.db" - subPath: "database.db" + # volumeMounts: + # - name: received-data + # mountPath: "/srv" mlflow: - enabled: true + enabled: false + image: repository: konstellation/kdl-mlflow pullPolicy: IfNotPresent diff --git a/project-operator/helm-charts/kdl-project/templates/_helpers.tpl b/project-operator/helm-charts/kdl-project/templates/_helpers.tpl index 7af954c2f..049398a95 100644 --- a/project-operator/helm-charts/kdl-project/templates/_helpers.tpl +++ b/project-operator/helm-charts/kdl-project/templates/_helpers.tpl @@ -1,12 +1,12 @@ {{/* -Expand the name of the chart. +Expand the name of the chart */}} {{- define "kdl-project.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} {{/* -Create a default fully qualified app name. +Create a default fully qualified app name We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} @@ -24,7 +24,7 @@ If release name contains chart name it will be used as a full name. {{- end }} {{/* -Create chart name and version as used by the chart label. +Create chart name and version as used by the chart label */}} {{- define "kdl-project.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} @@ -57,7 +57,7 @@ app.kubernetes.io/instance: {{ .Release.Name }} */}} {{/* -Expand the name of the chart. +Expand the name of the chart */}} {{- define "kdl-project.filebrowser.name" -}} {{- printf "%s-filebrowser" .Values.projectId | trunc 63 | trimSuffix "-" }} @@ -75,7 +75,7 @@ Create the name of the service account to use {{- end -}} {{/* -Default server component +Default filebowser component */}} {{- define "kdl-project.filebrowserComponentLabel" -}} kdl-project/component: filebrowser @@ -83,14 +83,14 @@ kdl-project/projectId: {{ .Values.projectId | quote }} {{- end -}} {{/* -Generate labels for server component +Generate labels for filebowser component */}} {{- define "kdl-project.filebrowserLabels" -}} {{- toYaml (merge ((include "kdl-project.labels" .) | fromYaml) ((include "kdl-project.filebrowserComponentLabel" .) | fromYaml)) }} {{- end }} {{/* -Generate selectorLabels for server component +Generate selectorLabels for filebowser component */}} {{- define "kdl-project.selectorFilebrowserLabels" -}} {{- toYaml (merge ((include "kdl-project.selectorLabels" .) | fromYaml) ((include "kdl-project.filebrowserComponentLabel" .) | fromYaml)) }} @@ -129,7 +129,7 @@ This works because Helm treats dictionaries as mutable objects and allows passin */}} {{/* -Expand the name of the chart. +Expand the name of the chart */}} {{- define "kdl-project.mlflow.name" -}} {{- printf "%s-mlflow" .Values.projectId | trunc 63 | trimSuffix "-" }} @@ -147,7 +147,7 @@ Create the name of the service account to use {{- end -}} {{/* -Default server component +Default MLflow component */}} {{- define "kdl-project.mlflowComponentLabel" -}} kdl-project/component: mlflow @@ -155,14 +155,14 @@ kdl-project/projectId: {{ .Values.projectId | quote }} {{- end -}} {{/* -Generate labels for server component +Generate labels for MLflow component */}} {{- define "kdl-project.mlflowLabels" -}} {{- toYaml (merge ((include "kdl-project.labels" .) | fromYaml) ((include "kdl-project.mlflowComponentLabel" .) | fromYaml)) }} {{- end }} {{/* -Generate selectorLabels for server component +Generate selectorLabels for MLflow component */}} {{- define "kdl-project.selectorMlflowLabels" -}} {{- toYaml (merge ((include "kdl-project.selectorLabels" .) | fromYaml) ((include "kdl-project.mlflowComponentLabel" .) | fromYaml)) }} diff --git a/project-operator/helm-charts/kdl-project/templates/filebrowser/configmap.yml b/project-operator/helm-charts/kdl-project/templates/filebrowser/configmap.yml index 695f4ceec..6687678da 100644 --- a/project-operator/helm-charts/kdl-project/templates/filebrowser/configmap.yml +++ b/project-operator/helm-charts/kdl-project/templates/filebrowser/configmap.yml @@ -2,26 +2,57 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "kdl-project.filebrowser.name" . }} - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "0" + name: {{ .Values.projectId }}-filebrowser-config labels: {{- include "kdl-project.filebrowserLabels" . | nindent 4 }} data: entrypoint.sh: | #!/bin/sh + set -e + + if [ -n "$AWS_S3_BUCKET" ]; then + echo "Mounting S3 bucket..." + + # minio authentication + if [ -n "$AWS_S3_ACCESS_KEY_ID" ] && [ -n "$AWS_S3_SECRET_ACCESS_KEY" ]; then + echo "$AWS_S3_ACCESS_KEY_ID:$AWS_S3_SECRET_ACCESS_KEY" > /etc/passwd-s3fs + chmod 600 /etc/passwd-s3fs + fi + + # bucket with basic options + s3fs "$AWS_S3_BUCKET" "$AWS_S3_MOUNT" \ + -o passwd_file=/etc/passwd-s3fs \ + -o url="$AWS_S3_URL" \ + -o allow_other \ + $S3FS_ARGS + + # wait until mount to be ready + while ! mountpoint -q "$AWS_S3_MOUNT"; do + echo "Waiting for S3 mount to be ready..." + sleep 1 + done + echo "S3 mount completed" + fi + + # filebrowser configuration + echo "Initializing Filebrowser..." /filebrowser config init /filebrowser config set --auth.method=noauth + + # KDL admin user + echo "Configuring KDL admin user..." /filebrowser users add kdladmin not_used_pass \ - --perm.admin=false \ - --perm.download=true \ - --perm.create=true \ - --perm.delete=true \ - --perm.execute=false \ - --perm.modify=true \ - --perm.rename=true \ - --perm.share=false \ - --lockPassword=true - /filebrowser + --perm.admin=false \ + --perm.download=true \ + --perm.create=false \ + --perm.delete=false \ + --perm.execute=false \ + --perm.modify=false \ + --perm.rename=false \ + --perm.share=false \ + --lockPassword=true + + # filebrowser + echo "Starting Filebrowser..." + exec /filebrowser {{- end }} diff --git a/project-operator/helm-charts/kdl-project/templates/filebrowser/deployment.yml b/project-operator/helm-charts/kdl-project/templates/filebrowser/deployment.yml index 98ead395d..4f5ff6bf1 100644 --- a/project-operator/helm-charts/kdl-project/templates/filebrowser/deployment.yml +++ b/project-operator/helm-charts/kdl-project/templates/filebrowser/deployment.yml @@ -37,6 +37,8 @@ spec: - name: filebrowser image: {{ .Values.filebrowser.image.repository }}:{{ .Values.filebrowser.image.tag }} imagePullPolicy: {{ .Values.filebrowser.image.pullPolicy }} + securityContext: + {{- toYaml .Values.filebrowser.securityContext | nindent 12 }} {{- with .Values.filebrowser.command }} command: {{- toYaml . | nindent 12 }} {{- end }} @@ -52,10 +54,10 @@ spec: containerPort: {{ $port.targetPort }} protocol: TCP {{- end }} + {{- with .Values.filebrowser.lifecycle }} lifecycle: - {{- with .Values.filebrowser.lifecycle }} {{- toYaml . | nindent 12 }} - {{- end }} + {{- end }} {{- if .Values.filebrowser.livenessProbe.enabled }} livenessProbe: {{- if .Values.filebrowser.livenessProbeCustom }} @@ -102,8 +104,6 @@ spec: {{- end }} {{- end }} envFrom: - - configMapRef: - name: {{ include "kdl-project.filebrowser.name" . }} {{- if .Values.filebrowser.envFromFiles }} {{- tpl (toYaml .Values.filebrowser.envFromFiles) . | nindent 12 }} {{- end }} @@ -111,7 +111,9 @@ spec: - name: FB_BASEURL value: /filebrowser/{{ .Values.projectId }} - name: FB_PORT - value: {{ .Values.filebrowser.env.FB_PORT | default (int .Values.filebrowser.service.targetPort | default .Values.filebrowser.service.port) }} + value: {{ .Values.filebrowser.env.FB_PORT | default (int .Values.filebrowser.service.targetPort | default .Values.filebrowser.service.port) | quote }} + - name: AWS_S3_BUCKET + value: {{ .Values.projectId | quote }} # Variables from secrets have precedence {{- $envList := dict }} {{- if .Values.filebrowser.envFromSecrets }} @@ -153,22 +155,19 @@ spec: - name: filebrowser-config mountPath: /entrypoint.sh subPath: entrypoint.sh - - name: received-data - mountPath: /srv - subPath: {{ .Values.projectId }} - {{- with .Values.filebrowser.volumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} + {{- with .Values.filebrowser.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} resources: {{- toYaml .Values.filebrowser.resources | nindent 12 }} - {{- if .Values.filebrowser.extraContainers }} - {{- toYaml .Values.filebrowser.extraContainers | nindent 8 }} - {{- end }} + {{- if .Values.filebrowser.extraContainers }} + {{- toYaml .Values.filebrowser.extraContainers | nindent 8 }} + {{- end }} terminationGracePeriodSeconds: {{ .Values.filebrowser.terminationGracePeriodSeconds }} volumes: - name: filebrowser-config configMap: - name: {{ include "kdl-project.filebrowser.name" . }} + name: {{ .Values.projectId }}-filebrowser-config defaultMode: 0777 {{- with .Values.filebrowser.volumes }} {{- toYaml . | nindent 8 }} diff --git a/project-operator/helm-charts/kdl-project/templates/mlflow/deployment.yml b/project-operator/helm-charts/kdl-project/templates/mlflow/deployment.yml index 99d1fb392..d15ff9f9a 100644 --- a/project-operator/helm-charts/kdl-project/templates/mlflow/deployment.yml +++ b/project-operator/helm-charts/kdl-project/templates/mlflow/deployment.yml @@ -37,6 +37,8 @@ spec: - name: mlflow image: {{ .Values.mlflow.image.repository }}:{{ .Values.mlflow.image.tag }} imagePullPolicy: {{ .Values.mlflow.image.pullPolicy }} + securityContext: + {{- toYaml .Values.mlflow.securityContext | nindent 12 }} command: - mlflow args: @@ -105,7 +107,7 @@ spec: {{- end }} env: - name: MLFLOW_DEFAULT_ARTIFACT_ROOT - value: s3://$(ARTIFACTS_BUCKET) + value: "s3://{{ .Values.projectId }}" # Variables from secrets have precedence {{- $envList := dict }} {{- if .Values.mlflow.envFromSecrets }} @@ -148,14 +150,14 @@ spec: - name: mlflow-tracking mountPath: /mlflow/tracking {{- end }} - {{- with .Values.mlflow.volumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} + {{- with .Values.mlflow.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} resources: {{- toYaml .Values.mlflow.resources | nindent 12 }} - {{- if .Values.mlflow.extraContainers }} - {{- toYaml .Values.mlflow.extraContainers | nindent 8 }} - {{- end }} + {{- if .Values.mlflow.extraContainers }} + {{- toYaml .Values.mlflow.extraContainers | nindent 8 }} + {{- end }} terminationGracePeriodSeconds: {{ .Values.mlflow.terminationGracePeriodSeconds }} volumes: {{- if .Values.mlflow.persistentVolume.enabled }} diff --git a/project-operator/helm-charts/kdl-project/values.yaml b/project-operator/helm-charts/kdl-project/values.yaml index effab4d81..4f6d5ccb5 100644 --- a/project-operator/helm-charts/kdl-project/values.yaml +++ b/project-operator/helm-charts/kdl-project/values.yaml @@ -28,11 +28,11 @@ filebrowser: # The image configuration for the base service image: # The repository of the image - repository: filebrowser/filebrowser + repository: konstellation/kdl-filebrowser # The pull policy for the image pullPolicy: IfNotPresent # The image tag - tag: "v2" + tag: "latest" # -- Specifies the secrets to use for pulling images from private registries # Leave empty if no secrets are required @@ -56,10 +56,30 @@ filebrowser: # -- Environment variables to configure application env: + # AWS_S3_ACCESS_KEY_ID: "xxx" + # AWS_S3_MOUNT: "/srv" + # AWS_S3_SECRET_ACCESS_KEY: "xxx" + # AWS_S3_URL: "http://minio:9000" FB_ADDRESS: "0.0.0.0" FB_DATABASE: /database.db FB_LOG: stdout FB_ROOT: /srv + # S3FS_ARGS: >- + # -o use_path_request_style + # -o use_cache=/cache + # -o ensure_diskfree=2048 + # -o max_stat_cache_size=100000 + # -o stat_cache_expire=300 + # -o enable_noobj_cache + # -o dbglevel=warn + # -o multipart_size=52 + # -o parallel_count=32 + # -o max_dirty_data=512 + # -o multireq_max=30 + # -o complement_stat + # -o notsup_compat_dir + # -o enable_content_md5 + # -o ro # -- Variables from secrets envFromSecrets: {} @@ -81,16 +101,6 @@ filebrowser: # - configMapRef: # name: - # -- Secrets values to create credentials and reference by envFromSecrets - # Generate Secret with following name: - - #
Ref: https://kubernetes.io/docs/concepts/configuration/secret/ - secrets: [] - # - name: secret-name - # data: - # my.key: |- - # my-content - # my_var: my-value - # -- Configure extra containers extraContainers: [] # - name: project-proxy @@ -257,18 +267,16 @@ filebrowser: #
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/ #
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ podSecurityContext: {} - # fsGroup: 2000 + # fsGroup: 1000 # -- Defines privilege and access control settings for a Container #
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/ #
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ securityContext: {} + # privileged: true # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 + # add: + # - SYS_ADMIN # -- Resources limits and requested #
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ @@ -301,19 +309,19 @@ filebrowser: #
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ #
Ref: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#create-a-pod-that-has-access-to-the-secret-data-through-a-volume volumes: [] - # - name: received-data - # persistentVolumeClaim: - # claimName: received-data-claim - # - name: foo - # secret: - # secretName: mysecret - # optional: false + # - name: cache-volume + # emptyDir: {} + # - name: fuse-device + # hostPath: + # path: /dev/fuse + # type: CharDevice # -- Additional volumeMounts on the output Deployment definition volumeMounts: [] - # - name: foo - # mountPath: "/etc/foo" - # readOnly: true + # - name: cache-volume + # mountPath: /cache + # - name: fuse-device + # mountPath: /dev/fuse # -- Node labels for pod assignment #
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector @@ -378,8 +386,8 @@ mlflow: # ref: https://mlflow.org/docs/latest/cli.html?highlight=Environment_variables#mlflow-server env: # ARTIFACTS_BUCKET: mlflow-artifacts - # AWS_ACCESS_KEY_ID: minio - # AWS_SECRET_ACCESS_KEY: minio123 + # AWS_ACCESS_KEY_ID: xxx + # AWS_SECRET_ACCESS_KEY: xxx # MLFLOW_S3_ENDPOINT_URL: "http://kdl-server-minio:9000" MLFLOW_BACKEND_STORE_URI: "sqlite:///mlflow.db" MLFLOW_HOST: "0.0.0.0" @@ -405,16 +413,6 @@ mlflow: # - configMapRef: # name: - # -- Secrets values to create credentials and reference by envFromSecrets - # Generate Secret with following name: - - #
Ref: https://kubernetes.io/docs/concepts/configuration/secret/ - secrets: [] - # - name: secret-name - # data: - # my.key: |- - # my-content - # my_var: my-value - # -- Configure extra containers extraContainers: [] # - name: project-proxy diff --git a/user-tools-operator/.gitignore b/user-tools-operator/.gitignore new file mode 100644 index 000000000..62fd3e399 --- /dev/null +++ b/user-tools-operator/.gitignore @@ -0,0 +1,14 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ diff --git a/user-tools-operator/Dockerfile b/user-tools-operator/Dockerfile index de895d640..eb03aa1cc 100644 --- a/user-tools-operator/Dockerfile +++ b/user-tools-operator/Dockerfile @@ -1,6 +1,6 @@ -FROM quay.io/operator-framework/helm-operator:v1.37 +FROM quay.io/operator-framework/helm-operator:v1.38 LABEL maintainer="Intelygenz - Konstellation Team" COPY watches.yaml ${HOME}/watches.yaml -COPY helm-charts/ ${HOME}/helm-charts/ +COPY helm-charts ${HOME}/helm-charts diff --git a/user-tools-operator/helm-charts/usertools/.helmignore b/user-tools-operator/helm-charts/kdl-user-tools/.helmignore similarity index 100% rename from user-tools-operator/helm-charts/usertools/.helmignore rename to user-tools-operator/helm-charts/kdl-user-tools/.helmignore diff --git a/user-tools-operator/helm-charts/kdl-user-tools/Chart.yaml b/user-tools-operator/helm-charts/kdl-user-tools/Chart.yaml new file mode 100644 index 000000000..d3cc8391e --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +type: application +name: kdl-user-tools +description: A Helm chart to deploy KDL user-tools +version: 1.0.0 +appVersion: 1.38.0 +sources: + - https://github.com/konstellation-io/kdl-server +home: https://www.konstellation.io +maintainers: + - name: ialejandro + email: ivan.alejandro@intelygenz.com + - name: alpiquero + email: angelluis.piquero@intelygenz.com + - name: danielchg + email: daniel.chavero@intelygenz.com +keywords: + - ia + - kdl + - kdl-server + - konstellation + - kubernetes + - machine learning diff --git a/user-tools-operator/helm-charts/kdl-user-tools/README.md b/user-tools-operator/helm-charts/kdl-user-tools/README.md new file mode 100644 index 000000000..5989a24d2 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/README.md @@ -0,0 +1,175 @@ +# kdl-user-tools + +A Helm chart to deploy KDL user-tools + +## Description + +The KDL User Tools operator automates the creation and management of personalized development environments for data scientists within a Kubernetes cluster. Each environment provides a complete, isolated workspace with integrated development tools, secure access controls, and collaborative features. + +## How works + +### Default values + +`values.yaml` file contains all default configurations for user development environments, including: + +* Resource allocations and limits +* Security settings and access controls +* Network policies and isolation rules +* Storage configurations and persistence +* Service endpoints and connectivity +* Development tool configurations + +### Overriding values from `kdl-server` Helm chart + +For example, if the default values specify: + +```yaml +vscodeRuntime: + resources: + limits: + memory: "4Gi" + cpu: "2" +``` + +A user-tools might override these with: + +```yaml +vscodeRuntime: + resources: + limits: + memory: "8Gi" + cpu: "4" + requests: + memory: "2Gi" + cpu: "500m" +``` + +## Components + +### VSCode Runtime + +* Pre-installed data science tools, frameworks and libraries necessary for model development +* Environment ensuring consistency across all development stages +* Built-in dependencies and configurations optimized for data science workflows +* An isolated workspace that maintains reproducibility of experiments and model development + +### Repository Cloner + +* Automatic repository synchronization +* Git credential management +* Repository access control +* Workspace initialization +* Code availability management + +## Example + +Creating a new development environment: + +```yaml +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + name: data-scientist-env +spec: + username: "data.scientist" + usernameSlug: "data-scientist" + vscodeRuntime: + image: + repository: konstellation/kdl-py + tag: "3.9" + persistentVolume: + enabled: true + size: "10Gi" +``` + +This creates a complete development environment with: + +* runtime access +* Python data science tools +* Persistent storage +* Security configurations +* Network policies + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| ialejandro | | | +| alpiquero | | | +| danielchg | | | + +## Prerequisites + +* Helm 3+ +* Kubernetes 1.26+ + +## CI values + +Go to [ci](./ci) directory to see some examples of how to use this chart. + +```console +helm template test . -f ci/ci-values.yaml +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity for pod assignment
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity | +| autoscaling | object | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Autoscaling with CPU or memory utilization percentage
Ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ | +| extraContainers | list | `[]` | Configure extra containers | +| fullnameOverride | string | `""` | String to fully override kdl-user-tools.fullname template | +| imagePullSecrets | list | `[]` | Specifies the secrets to use for pulling images from private registries Leave empty if no secrets are required E.g. imagePullSecrets: - name: myRegistryKeySecretName | +| initContainers | list | `[{"command":["sh","/generate-kubeconfig.sh"],"image":"alpine/k8s:1.31.2","imagePullPolicy":"IfNotPresent","name":"create-kubeconfig","volumeMounts":[{"mountPath":"/home/coder","name":"data"},{"mountPath":"/kubeconfig.tpl","name":"kubeconfig-tpl-configmap","subPath":"kubeconfig.tpl"},{"mountPath":"/generate-kubeconfig.sh","name":"kubeconfig-tpl-configmap","subPath":"generate-kubeconfig.sh"}]},{"command":["sh","-c","mkdir -p /home/kdl/.ssh && chown 1000:1000 /home/kdl/.ssh"],"image":"busybox:stable","imagePullPolicy":"IfNotPresent","name":"create-ssh-folder","volumeMounts":[{"mountPath":"/home/kdl","name":"data"}]}]` | Configure additional containers
Ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ | +| kubeconfig | object | `{"enabled":false}` | If enabled, users will be able to download a kubeconfig file, so they can attach an external terminal/IDE to the vscodeRuntime running inside. | +| minReadySeconds | int | `0` | Minimum number of seconds for which a newly created pod should be ready without any containers crashing | +| nameOverride | string | `""` | String to partially override kdl-user-tools.fullname template (will maintain the release name) | +| networkPolicy | object | `{"egress":[],"enabled":false,"ingress":[],"policyTypes":[]}` | NetworkPolicy configuration
Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ | +| networkPolicy.enabled | bool | `false` | Enable or disable NetworkPolicy | +| networkPolicy.policyTypes | list | `[]` | Policy types | +| nodeSelector | object | `{}` | Node labels for pod assignment
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | +| persistentVolume | object | `{"accessModes":["ReadWriteOnce"],"enabled":true,"size":"1Gi","storageClass":""}` | Persistent Volume configuration
Ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ | +| persistentVolume.accessModes | list | `["ReadWriteOnce"]` | Persistent Volume access modes Must match those of existing PV or dynamic provisioner
Ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ | +| persistentVolume.enabled | bool | `true` | Enable or disable persistence | +| persistentVolume.size | string | `"1Gi"` | Persistent Volume size | +| persistentVolume.storageClass | string | `""` | Persistent Volume Storage Class If defined, storageClassName: If set to "-", storageClassName: "", which disables dynamic provisioning If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner. (gp2 on AWS, standard on GKE, AWS & OpenStack) | +| podAnnotations | object | `{}` | Configure annotations on Pods | +| podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":null}` | Pod Disruption Budget
Ref: https://kubernetes.io/docs/reference/kubernetes-api/policy-resources/pod-disruption-budget-v1/ | +| podLabels | object | `{}` | Configure labels on Pods | +| podManagementPolicy | string | `"OrderedReady"` | Ordering options for updates Valid values: "OrderedReady" or "Parallel" | +| podSecurityContext | object | `{"fsGroup":1000}` | Defines privilege and access control settings for a Pod
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| replicaCount | int | `1` | Number of replicas Specifies the number of replicas for the service | +| repoCloner | object | `{"args":[],"command":[],"env":{},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"homePath":"/home/kdl","image":{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-repo-cloner","tag":"latest"},"lifecycle":{},"volumeMounts":[]}` | Module cloning external repositories of the projects in which the user participates. This way they are available for code-server to be able to work with it.
Ref: https://github.com/konstellation-io/kdl-server/tree/main/repo-cloner | +| repoCloner.args | list | `[]` | Configure args
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | +| repoCloner.command | list | `[]` | Configure command
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | +| repoCloner.env | object | `{}` | Environment variables to configure application | +| repoCloner.envFromConfigMap | object | `{}` | Variables from configMap | +| repoCloner.envFromFiles | list | `[]` | Load all variables from files
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables | +| repoCloner.envFromSecrets | object | `{}` | Variables from secrets | +| repoCloner.homePath | string | `"/home/kdl"` | Mountpath where mount data | +| repoCloner.lifecycle | object | `{}` | Configure lifecycle hooks
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
Ref: https://learnk8s.io/graceful-shutdown | +| repoCloner.volumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition | +| resources | object | `{}` | Resources limits and requested
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | +| securityContext | object | `{}` | Defines privilege and access control settings for a Container
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| serviceAccount | object | `{"annotations":{},"automount":true,"create":true,"name":""}` | Enable creation of ServiceAccount
Ref: https://kubernetes.io/docs/concepts/security/service-accounts/ | +| sharedVolume | object | `{"enabled":false,"name":""}` | String to set external volume to use on user-tools workspace | +| sharedVolume.enabled | bool | `false` | Enable or disable sharedVolume use | +| terminationGracePeriodSeconds | int | `30` | Configure Pod termination grace period
Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination | +| tolerations | list | `[]` | Tolerations for pod assignment
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | +| topologySpreadConstraints | list | `[]` | Control how Pods are spread across your cluster
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#example-multiple-topologyspreadconstraints | +| updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":1,"partition":0},"type":"RollingUpdate"}` | This feature can be used to upgrade the container images, resource requests and/or limits, labels, and annotations of the Pods
Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ | +| updateStrategy.type | string | `"RollingUpdate"` | StatefulSet update strategy policy Valid values: "RollingUpdate" or "OnDelete" | +| username | string | `"replaced-by-kdl-api"` | String from KDL API | +| usernameSlug | string | `"replaced-by-kdl-api"` | String from KDL API used slug replacer
Ref: https://pkg.go.dev/github.com/gosimple/slug | +| volumes | list | `[]` | Additional volumes on the output Deployment definition
Ref: https://kubernetes.io/docs/concepts/storage/volumes/
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/
Ref: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#create-a-pod-that-has-access-to-the-secret-data-through-a-volume | +| vscodeRuntime | object | `{"args":["-c","trap : TERM INT; sleep infinity & wait"],"command":["/bin/bash"],"env":{},"envFromConfigMap":{},"envFromFiles":[],"envFromSecrets":{},"homePath":"/home/coder","image":{"pullPolicy":"IfNotPresent","repository":"konstellation/kdl-py","tag":"3.9"},"lifecycle":{},"resources":{},"volumeMounts":[]}` | Runtime refers to a pre-configured containerized environment, equipped with the tools, libraries, and dependencies which data scientists need to develop, test and deploy models.
Ref: https://github.com/konstellation-io/konstellation-runtimes | +| vscodeRuntime.args | list | `["-c","trap : TERM INT; sleep infinity & wait"]` | Configure args
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | +| vscodeRuntime.command | list | `["/bin/bash"]` | Configure command
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ | +| vscodeRuntime.env | object | `{}` | Environment variables to configure application | +| vscodeRuntime.envFromConfigMap | object | `{}` | Variables from configMap | +| vscodeRuntime.envFromFiles | list | `[]` | Load all variables from files
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables | +| vscodeRuntime.envFromSecrets | object | `{}` | Variables from secrets | +| vscodeRuntime.homePath | string | `"/home/coder"` | Mountpath where mount data | +| vscodeRuntime.lifecycle | object | `{}` | Configure lifecycle hooks
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/
Ref: https://learnk8s.io/graceful-shutdown | +| vscodeRuntime.resources | object | `{}` | Resources limits and requested
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | +| vscodeRuntime.volumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition | diff --git a/user-tools-operator/helm-charts/kdl-user-tools/README.md.gotmpl b/user-tools-operator/helm-charts/kdl-user-tools/README.md.gotmpl new file mode 100644 index 000000000..93a7c71e7 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/README.md.gotmpl @@ -0,0 +1,110 @@ +# {{ template "chart.name" . }} + +{{ template "chart.description" . }} + +## Description + +The KDL User Tools operator automates the creation and management of personalized development environments for data scientists within a Kubernetes cluster. Each environment provides a complete, isolated workspace with integrated development tools, secure access controls, and collaborative features. + +## How works + +### Default values + +`values.yaml` file contains all default configurations for user development environments, including: + +* Resource allocations and limits +* Security settings and access controls +* Network policies and isolation rules +* Storage configurations and persistence +* Service endpoints and connectivity +* Development tool configurations + +### Overriding values from `kdl-server` Helm chart + +For example, if the default values specify: + +```yaml +vscodeRuntime: + resources: + limits: + memory: "4Gi" + cpu: "2" +``` + +A user-tools might override these with: + +```yaml +vscodeRuntime: + resources: + limits: + memory: "8Gi" + cpu: "4" + requests: + memory: "2Gi" + cpu: "500m" +``` + +## Components + +### VSCode Runtime + +* Pre-installed data science tools, frameworks and libraries necessary for model development +* Environment ensuring consistency across all development stages +* Built-in dependencies and configurations optimized for data science workflows +* An isolated workspace that maintains reproducibility of experiments and model development + +### Repository Cloner + +* Automatic repository synchronization +* Git credential management +* Repository access control +* Workspace initialization +* Code availability management + +## Example + +Creating a new development environment: + +```yaml +apiVersion: kdl.konstellation.io/v1 +kind: KDLUserTools +metadata: + name: data-scientist-env +spec: + username: "data.scientist" + usernameSlug: "data-scientist" + vscodeRuntime: + image: + repository: konstellation/kdl-py + tag: "3.9" + persistentVolume: + enabled: true + size: "10Gi" +``` + +This creates a complete development environment with: + +* runtime access +* Python data science tools +* Persistent storage +* Security configurations +* Network policies + +{{ template "chart.maintainersSection" . }} + +## Prerequisites + +* Helm 3+ +* Kubernetes 1.26+ + +{{ template "chart.requirementsSection" . }} + +## CI values + +Go to [ci](./ci) directory to see some examples of how to use this chart. + +```console +helm template test . -f ci/ci-values.yaml +``` + +{{ template "chart.valuesSection" . }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/ci/ci-values.yaml b/user-tools-operator/helm-charts/kdl-user-tools/ci/ci-values.yaml new file mode 100644 index 000000000..17d312f41 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/ci/ci-values.yaml @@ -0,0 +1,153 @@ +#### +## THESE VALUES ONLY USE TO MAKE HELM DIFF +## OR HELM TEMPLATE +#### + +# User identification +username: "john.doe" +usernameSlug: "john-doe" # Slugified version for resource naming + +# Shared volume configuration +sharedVolume: + enabled: true + name: "shared-workspace" + +# External IDE connection configuration +kubeconfig: + enabled: true + externalServerUrl: "https://k8s.example.com:6443" + +# Deployment configuration +replicaCount: 1 +podManagementPolicy: "OrderedReady" + +# Service account configuration +serviceAccount: + create: true + automount: true + annotations: + kubernetes.io/example-annotation: "value" + +# Security settings +podSecurityContext: + fsGroup: 1000 + +securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + +# Storage configuration +persistentVolume: + enabled: true + size: "10Gi" + accessModes: + - ReadWriteOnce + storageClass: "standard" + +# Network policies +networkPolicy: + enabled: true + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app: kdl-server + ports: + - protocol: TCP + port: 8080 + egress: + - to: + - namespaceSelector: + matchLabels: + name: default + ports: + - protocol: TCP + port: 443 + +# Resource management +resources: + limits: + cpu: "2" + memory: "4Gi" + requests: + cpu: "500m" + memory: "1Gi" + +# High availability configuration +podDisruptionBudget: + enabled: true + maxUnavailable: 1 + +# Repository cloner configuration +repoCloner: + image: + repository: konstellation/kdl-repo-cloner + tag: "latest" + pullPolicy: IfNotPresent + + homePath: "/home/kdl" + + command: + - /bin/sh + args: + - -c + - /entrypoint.sh + + env: + KDL_SERVER_MONGODB_URI: "mongodb://user:pass@mongodb:27017/db?authSource=user&authMechanism=SCRAM-SHA-256" + +# VSCode runtime configuration +vscodeRuntime: + image: + repository: konstellation/python-ds-runtime + tag: "3.9" + pullPolicy: IfNotPresent + + homePath: "/home/coder" + + command: + - /bin/bash + args: + - "-c" + - "trap : TERM INT; sleep infinity & wait" + + env: + MINIO_ACCESS_KEY: "minio" + MINIO_SECRET_KEY: "minio123" + MINIO_ENDPOINT: "http://minio:9000" + +# Node scheduling +nodeSelector: + kubernetes.io/os: linux + +tolerations: + - key: "dedicated" + operator: "Equal" + value: "data-science" + effect: "NoSchedule" + +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: gpu + operator: In + values: + - "true" + +# Pod spreading +topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app: kdlusertools diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/NOTES.txt b/user-tools-operator/helm-charts/kdl-user-tools/templates/NOTES.txt new file mode 100644 index 000000000..6c7996148 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/NOTES.txt @@ -0,0 +1,20 @@ +# KDLUserTools + +=== Access information === +To access your VSCode development environment: + +1. Wait for the StatefulSet to be ready: + $ kubectl get sts -n {{ .Release.Namespace }} {{ include "kdl-user-tools.fullname" . }} + +2. Verify all pods are running: + $ kubectl get pods -n {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "kdl-user-tools.name" . }}" + +3. Connect to your VSCode runtime: + $ kubectl exec -it -n {{ .Release.Namespace }} {{ include "kdl-user-tools.fullname" . }}-0 -c vscode-runtime -- bash + +=== Security notice === +* Do not share your access credentials with others +* Always follow security best practices when handling sensitive data +* Regularly commit and push your work to prevent data loss + +Visit https://github.com/konstellation-io/kdl-server for documentation and updates. diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/_helpers.tpl b/user-tools-operator/helm-charts/kdl-user-tools/templates/_helpers.tpl new file mode 100644 index 000000000..51a799b84 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/_helpers.tpl @@ -0,0 +1,90 @@ +{{/* +Expand the name of the chart +*/}} +{{- define "kdl-user-tools.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kdl-user-tools.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- if .Values.nameOverride }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label +*/}} +{{- define "kdl-user-tools.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kdl-user-tools.labels" -}} +helm.sh/chart: {{ include "kdl-user-tools.chart" . }} +{{ include "kdl-user-tools.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kdl-user-tools.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kdl-user-tools.fullname" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +kdl-user-tools/component: user-tools +kdl-user-tools/usernameSlug: {{ .Values.usernameSlug | quote }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "kdl-user-tools.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{- default (include "kdl-user-tools.fullname" .) .Values.serviceAccount.name -}} +{{- else -}} +{{- default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Ref: https://github.com/aws/karpenter-provider-aws/blob/main/charts/karpenter/templates/_helpers.tpl +Patch the label selector on an object +This template will add a labelSelector using matchLabels to the object referenced at _target if there is no labelSelector specified. +The matchLabels are created with the selectorLabels template. +This works because Helm treats dictionaries as mutable objects and allows passing them by reference. +*/}} +{{- define "kdl-user-tools.patchSelectorUserToolsLabels" -}} +{{- if not (hasKey ._target "labelSelector") }} +{{- $selectorLabels := (include "kdl-user-tools.selectorLabels" .) | fromYaml }} +{{- $_ := set ._target "labelSelector" (dict "matchLabels" $selectorLabels) }} +{{- end }} +{{- end }} + +{{/* +Ref: https://github.com/aws/karpenter-provider-aws/blob/main/charts/karpenter/templates/_helpers.tpl +Patch topology spread constraints +This template uses the kdl-user-tools.selectorLabels template to add a labelSelector to topologySpreadConstraints if one isn't specified. +This works because Helm treats dictionaries as mutable objects and allows passing them by reference. +*/}} +{{- define "kdl-user-tools.patchTopologySpreadConstraintsUserTools" -}} +{{- range $constraint := .Values.topologySpreadConstraints }} +{{- include "kdl-user-tools.patchSelectorUserToolsLabels" (merge (dict "_target" $constraint (include "kdl-user-tools.selectorLabels" $)) $) }} +{{- end }} +{{- end }} diff --git a/user-tools-operator/helm-charts/usertools/templates/kubeconfig-tpl-configmap.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/configmap-kubeconfig.yaml similarity index 91% rename from user-tools-operator/helm-charts/usertools/templates/kubeconfig-tpl-configmap.yaml rename to user-tools-operator/helm-charts/kdl-user-tools/templates/configmap-kubeconfig.yaml index e4507738b..09a91e3de 100644 --- a/user-tools-operator/helm-charts/usertools/templates/kubeconfig-tpl-configmap.yaml +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/configmap-kubeconfig.yaml @@ -1,9 +1,9 @@ apiVersion: v1 kind: ConfigMap metadata: - name: kubeconfig-{{ .Values.usernameSlug }}-tpl-configmap + name: {{ include "kdl-user-tools.fullname" . }}-kubeconfig labels: - app: kubeconfig-{{ .Values.usernameSlug }}-tpl-configmap + {{- include "kdl-user-tools.labels" . | nindent 4 }} data: generate-kubeconfig.sh: |+ diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/hpa.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/hpa.yaml new file mode 100644 index 000000000..ab6f88d6e --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "kdl-user-tools.fullname" . }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "kdl-user-tools.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/networkpolicy.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/networkpolicy.yaml new file mode 100644 index 000000000..d40892eab --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/networkpolicy.yaml @@ -0,0 +1,48 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "kdl-user-tools.fullname" . }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 4 }} +spec: + {{- if and (not .Values.networkPolicy.policyTypes) (not .Values.networkPolicy.ingress) (not .Values.networkPolicy.egress) }} + podSelector: {} + {{- else }} + podSelector: + matchLabels: + {{- include "kdl-user-tools.selectorLabels" . | nindent 6 }} + {{- end }} + + {{- if .Values.networkPolicy.policyTypes }} + {{- with .Values.networkPolicy.policyTypes }} + policyTypes: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- else }} + policyTypes: + - Ingress + - Egress + {{- end }} + + {{- if .Values.networkPolicy.ingress }} + {{- with .Values.networkPolicy.ingress }} + ingress: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- else }} + ingress: + - {} + {{- end }} + + {{- if .Values.networkPolicy.egress }} + {{- with .Values.networkPolicy.egress }} + egress: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- else }} + egress: + - {} + {{- end }} + +{{- end }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/pdb.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/pdb.yaml new file mode 100644 index 000000000..a14baf7b4 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/pdb.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "kdl-user-tools.fullname" . }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "kdl-user-tools.selectorLabels" . | nindent 6 }} + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} +{{- end }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/role.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/role.yaml new file mode 100644 index 000000000..31f39c055 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/role.yaml @@ -0,0 +1,29 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "kdl-user-tools.fullname" . }} +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - list +- apiGroups: + - "" + resources: + - pods/exec + resourceNames: + - "{{ include "kdl-user-tools.fullname" . }}-0" + verbs: + - create +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - create + - delete diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/rolebinding.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/rolebinding.yaml new file mode 100644 index 000000000..2e8df1d1e --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/rolebinding.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "kdl-user-tools.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "kdl-user-tools.serviceAccountName" . }} +roleRef: + kind: Role + name: {{ include "kdl-user-tools.fullname" . }} + apiGroup: rbac.authorization.k8s.io diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/serviceaccount.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/serviceaccount.yaml new file mode 100644 index 000000000..e59b24e5a --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kdl-user-tools.serviceAccountName" . }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount | default "false" }} +{{- end }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/templates/statefulset.yaml b/user-tools-operator/helm-charts/kdl-user-tools/templates/statefulset.yaml new file mode 100644 index 000000000..f1ac58d0d --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/templates/statefulset.yaml @@ -0,0 +1,258 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "kdl-user-tools.fullname" . }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 4 }} +spec: + serviceName: {{ include "kdl-user-tools.fullname" . }} + podManagementPolicy: {{ .Values.podManagementPolicy | default "OrderedReady" }} + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + minReadySeconds: {{ .Values.minReadySeconds | default 0 }} + updateStrategy: + type: {{ .Values.updateStrategy.type | default "RollingUpdate" }} + {{- if eq (.Values.updateStrategy.type | default "RollingUpdate") "OnDelete" }} + rollingUpdate: null + {{- else if .Values.updateStrategy.rollingUpdate }} + rollingUpdate: + {{- toYaml .Values.updateStrategy.rollingUpdate | nindent 6 }} + {{- end }} + selector: + matchLabels: + {{- include "kdl-user-tools.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "kdl-user-tools.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 8 }} + serviceAccountName: {{ include "kdl-user-tools.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: repo-cloner + image: {{ .Values.repoCloner.image.repository }}:{{ .Values.repoCloner.image.tag }} + imagePullPolicy: {{ .Values.repoCloner.image.pullPolicy }} + securityContext: + {{- toYaml .Values.repoCloner.securityContext | nindent 12 }} + {{- with .Values.repoCloner.command }} + command: {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.repoCloner.args }} + args: {{- toYaml . | nindent 12 }} + {{- end }} + lifecycle: + {{- with .Values.repoCloner.lifecycle }} + {{- toYaml . | nindent 12 }} + {{- end }} + envFrom: + {{- if .Values.repoCloner.envFromFiles }} + {{- tpl (toYaml .Values.repoCloner.envFromFiles) . | nindent 12 }} + {{- end }} + env: + - name: KDL_USER_NAME + value: {{ .Values.username | quote }} + # Variables from secrets have precedence + {{- $envList := dict }} + {{- if .Values.repoCloner.envFromSecrets }} + {{- range $key, $value := .Values.repoCloner.envFromSecrets }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + valueFrom: + secretKeyRef: + name: {{ $value.name }} + key: {{ $value.key | default $key }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + # Variables from configmap have precedence + {{- if .Values.repoCloner.envFromConfigMap }} + {{- range $key, $value := .Values.repoCloner.envFromConfigMap }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + valueFrom: + configMapKeyRef: + name: {{ $value.name }} + key: {{ $value.key | default $key }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + # Variables in plain text if they were not already added from secrets + {{- if .Values.repoCloner.env }} + {{- range $key, $value := .Values.repoCloner.env }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + value: {{ $value | quote }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + volumeMounts: + {{- if .Values.persistentVolume.enabled }} + - name: data + mountPath: {{ .Values.repoCloner.homePath }} + {{- end }} + - name: {{ .Values.usernameSlug }}-ssh-keys-vol + mountPath: {{ .Values.repoCloner.homePath }}/.ssh/id_rsa + subPath: id_rsa + readOnly: true + {{- with .Values.repoCloner.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.repoCloner.resources | nindent 12 }} + - name: vscode-runtime + image: {{ .Values.vscodeRuntime.image.repository }}:{{ .Values.vscodeRuntime.image.tag }} + imagePullPolicy: {{ .Values.vscodeRuntime.image.pullPolicy }} + securityContext: + {{- toYaml .Values.vscodeRuntime.securityContext | nindent 12 }} + {{- with .Values.vscodeRuntime.command }} + command: {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.vscodeRuntime.args }} + args: {{- toYaml . | nindent 12 }} + {{- end }} + lifecycle: + {{- with .Values.vscodeRuntime.lifecycle }} + {{- toYaml . | nindent 12 }} + {{- end }} + envFrom: + {{- if .Values.vscodeRuntime.envFromFiles }} + {{- tpl (toYaml .Values.vscodeRuntime.envFromFiles) . | nindent 12 }} + {{- end }} + env: + # Variables from secrets have precedence + {{- $envList := dict }} + {{- if .Values.vscodeRuntime.envFromSecrets }} + {{- range $key, $value := .Values.vscodeRuntime.envFromSecrets }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + valueFrom: + secretKeyRef: + name: {{ $value.name }} + key: {{ $value.key | default $key }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + # Variables from configmap have precedence + {{- if .Values.vscodeRuntime.envFromConfigMap }} + {{- range $key, $value := .Values.vscodeRuntime.envFromConfigMap }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + valueFrom: + configMapKeyRef: + name: {{ $value.name }} + key: {{ $value.key | default $key }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + # Variables in plain text if they were not already added from secrets + {{- if .Values.vscodeRuntime.env }} + {{- range $key, $value := .Values.vscodeRuntime.env }} + {{- if not (hasKey $envList $key) }} + - name: {{ $key | upper }} + value: {{ $value | quote }} + {{- $_ := set $envList $key true }} + {{- end }} + {{- end }} + {{- end }} + volumeMounts: + {{- if .Values.persistentVolume.enabled }} + - name: data + mountPath: {{ .Values.vscodeRuntime.homePath }} + {{- end }} + {{- if .Values.sharedVolume.enabled }} + - name: {{ .Values.sharedVolume.name }} + mountPath: {{ .Values.vscodeRuntime.homePath }}/shared-storage + readOnly: false + {{- end }} + - name: {{ .Values.usernameSlug }}-ssh-keys-vol + mountPath: {{ .Values.vscodeRuntime.homePath }}/.ssh/id_rsa + subPath: id_rsa + readOnly: true + {{- with .Values.vscodeRuntime.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.vscodeRuntime.resources | nindent 12 }} + {{- if .Values.extraContainers }} + {{- toYaml .Values.extraContainers | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + volumes: + - name: kubeconfig-tpl-configmap + configMap: + name: {{ include "kdl-user-tools.fullname" . }}-kubeconfig + {{- if .Values.sharedVolume.enabled }} + - name: {{ .Values.sharedVolume.name }} + persistentVolumeClaim: + claimName: {{ .Values.sharedVolume.name }} + readOnly: false + {{- end }} + - name: {{ .Values.usernameSlug }}-ssh-keys-vol + secret: + secretName: {{ .Values.usernameSlug }}-ssh-keys + items: + - key: KDL_USER_PRIVATE_SSH_KEY + path: id_rsa + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + {{- $_ := include "kdl-user-tools.patchTopologySpreadConstraintsUserTools" $ }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.persistentVolume.enabled }} + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: + {{- range .Values.persistentVolume.accessModes }} + - {{ . | quote }} + {{- end }} + {{- if .Values.persistentVolume.storageClass }} + {{- if (eq "-" .Values.persistentVolume.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.persistentVolume.storageClass | quote }} + {{- end }} + {{- end }} + {{- if .Values.persistentVolume.volumeBindingMode }} + volumeBindingMode: {{ .Values.persistentVolume.volumeBindingMode | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistentVolume.size | quote }} + {{- end }} diff --git a/user-tools-operator/helm-charts/kdl-user-tools/values.yaml b/user-tools-operator/helm-charts/kdl-user-tools/values.yaml new file mode 100644 index 000000000..613c5f831 --- /dev/null +++ b/user-tools-operator/helm-charts/kdl-user-tools/values.yaml @@ -0,0 +1,408 @@ +# Default values for kdl-user-tools +# This is a YAML-formatted file +# Declare variables to be passed into your templates + +# -- String to partially override kdl-user-tools.fullname template (will maintain the release name) +nameOverride: "" + +# -- String to fully override kdl-user-tools.fullname template +fullnameOverride: "" + +# -- String from KDL API +username: "replaced-by-kdl-api" + +# -- String from KDL API used slug replacer +#
Ref: https://pkg.go.dev/github.com/gosimple/slug +usernameSlug: "replaced-by-kdl-api" + +# -- String to set external volume to use on user-tools workspace +sharedVolume: + # -- Enable or disable sharedVolume use + enabled: false + name: "" + +# -- If enabled, users will be able to download a kubeconfig file, so they can attach an +# external terminal/IDE to the vscodeRuntime running inside. +kubeconfig: + enabled: false + + ## External cluster address to be able to connect to it from the outside. + # externalServerUrl: https://192.168.0.21:16443 + +# -- Number of replicas +# Specifies the number of replicas for the service +replicaCount: 1 + +# -- Specifies the secrets to use for pulling images from private registries +# Leave empty if no secrets are required +# E.g. +# imagePullSecrets: +# - name: myRegistryKeySecretName +imagePullSecrets: [] + +# -- This feature can be used to upgrade the container images, resource requests and/or limits, +# labels, and annotations of the Pods +#
Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ +updateStrategy: + # -- StatefulSet update strategy policy + # Valid values: "RollingUpdate" or "OnDelete" + type: RollingUpdate + + # Specific configuration for RollingUpdate + # Only applies if type: RollingUpdate + rollingUpdate: + # Maximum number of pods that can be scheduled above the desired number of pods + # during an update + partition: 0 + # Maximum number of pods that can be unavailable during the update + maxUnavailable: 1 + +# -- Minimum number of seconds for which a newly created pod should be ready without any +# containers crashing +minReadySeconds: 0 + +# -- Ordering options for updates +# Valid values: "OrderedReady" or "Parallel" +podManagementPolicy: OrderedReady + +# -- Enable creation of ServiceAccount +#
Ref: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use + # If not set and create is true, a name is generated using the fullname template + name: "" + +# -- Configure extra containers +extraContainers: [] + # - name: project-proxy + # image: nginx:alpine + # command: ['sh', '-c', 'echo "Hello, World!"'] + +# -- Configure additional containers +#
Ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ +initContainers: + - name: create-kubeconfig + image: alpine/k8s:1.31.2 + imagePullPolicy: IfNotPresent + command: + - sh + - /generate-kubeconfig.sh + volumeMounts: + - name: data + mountPath: /home/coder + - name: kubeconfig-tpl-configmap + mountPath: /kubeconfig.tpl + subPath: kubeconfig.tpl + - name: kubeconfig-tpl-configmap + mountPath: /generate-kubeconfig.sh + subPath: generate-kubeconfig.sh + - name: create-ssh-folder + image: busybox:stable + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - mkdir -p /home/kdl/.ssh && chown 1000:1000 /home/kdl/.ssh + volumeMounts: + - name: data + mountPath: /home/kdl + +# -- NetworkPolicy configuration +#
Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +networkPolicy: + # -- Enable or disable NetworkPolicy + enabled: false + # -- Policy types + policyTypes: [] + # - Ingress + # - Egress + ingress: [] + # - from: + # - ipBlock: + # cidr: 172.17.0.0/16 + # except: + # - 172.17.1.0/24 + # - namespaceSelector: + # matchLabels: + # project: myproject + # - podSelector: + # matchLabels: + # role: frontend + # ports: + # - protocol: TCP + # port: 6379 + egress: [] + # - to: + # - ipBlock: + # cidr: 10.0.0.0/24 + # ports: + # - protocol: TCP + # port: 5978 + +# -- Configure Pod termination grace period +#
Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination +terminationGracePeriodSeconds: 30 + +# -- Configure annotations on Pods +podAnnotations: {} + +# -- Configure labels on Pods +podLabels: {} + # runtimeId: "replaced-by-kdl-apiaaaa" + # capabilityId: "replaced-by-kdl-apiaaaa" + +# -- Defines privilege and access control settings for a Pod +#
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/ +#
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +podSecurityContext: + fsGroup: 1000 + +# -- Defines privilege and access control settings for a Container +#
Ref: https://kubernetes.io/docs/concepts/security/pod-security-standards/ +#
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +# -- Resources limits and requested +#
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# -- Pod Disruption Budget +#
Ref: https://kubernetes.io/docs/reference/kubernetes-api/policy-resources/pod-disruption-budget-v1/ +podDisruptionBudget: + enabled: false + maxUnavailable: 1 + minAvailable: + +# -- Autoscaling with CPU or memory utilization percentage +#
Ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# -- Persistent Volume configuration +#
Ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ +persistentVolume: + # -- Enable or disable persistence + enabled: true + + # -- Persistent Volume access modes + # Must match those of existing PV or dynamic provisioner + #
Ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ + accessModes: + - ReadWriteOnce + + # -- Persistent Volume size + size: 1Gi + + # -- Persistent Volume Storage Class + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default provisioner. (gp2 on AWS, standard on + # GKE, AWS & OpenStack) + storageClass: "" + +# -- Additional volumes on the output Deployment definition +#
Ref: https://kubernetes.io/docs/concepts/storage/volumes/ +#
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ +#
Ref: https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#create-a-pod-that-has-access-to-the-secret-data-through-a-volume +volumes: [] +# - name: received-data +# persistentVolumeClaim: +# claimName: received-data-claim +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# -- Node labels for pod assignment +#
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector +nodeSelector: {} + +# -- Tolerations for pod assignment +#
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ +tolerations: [] + +# -- Affinity for pod assignment +#
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity +affinity: {} + +# -- Control how Pods are spread across your cluster +#
Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#example-multiple-topologyspreadconstraints +topologySpreadConstraints: [] +# - maxSkew: 1 +# topologyKey: zone +# whenUnsatisfiable: DoNotSchedule + +# -- Module cloning external repositories of the projects in which the user participates. This way they are available +# for code-server to be able to work with it. +#
Ref: https://github.com/konstellation-io/kdl-server/tree/main/repo-cloner +repoCloner: + image: + # The repository of the image + repository: konstellation/kdl-repo-cloner + # The pull policy for the image + pullPolicy: IfNotPresent + # The image tag + tag: "latest" + + # -- Mountpath where mount data + homePath: "/home/kdl" + + # -- Configure args + #
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ + args: [] + # - -c + # - /entrypoint.sh + + # -- Configure command + #
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ + command: [] + # - /bin/sh + + # -- Environment variables to configure application + env: {} + # KDL_SERVER_MONGODB_URI: "mongodb://user:pass@mongodb:27017/db?authSource=user&authMechanism=SCRAM-SHA-256" + + # -- Variables from secrets + envFromSecrets: {} + # MY_VARIABLE: + # name: + # key: secret_key + + # -- Variables from configMap + envFromConfigMap: {} + # MY_VARIABLE: + # name: + # key: key + + # -- Load all variables from files + #
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables + envFromFiles: [] + # - secretRef: + # name: + # - configMapRef: + # name: + + # -- Additional volumeMounts on the output Deployment definition + volumeMounts: [] + # - name: foo + # mountPath: "/etc/foo" + # readOnly: true + + # -- Configure lifecycle hooks + #
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ + #
Ref: https://learnk8s.io/graceful-shutdown + lifecycle: {} + # preStop: + # exec: + # command: ["sh", "-c", "sleep 10"] + # postStart: + # exec: + # command: + # - "/bin/sh" + # - "-c" + # - "ssh-keyscan -H keycloak >> /app/.ssh/known_hosts" + +# -- Runtime refers to a pre-configured containerized environment, equipped with the tools, +# libraries, and dependencies which data scientists need to develop, test and deploy models. +#
Ref: https://github.com/konstellation-io/konstellation-runtimes +vscodeRuntime: + image: + # The repository of the image (replaced-by-kdl-api) + repository: "konstellation/kdl-py" + # The pull policy for the image + pullPolicy: IfNotPresent + # The image tag (replaced-by-kdl-api) + tag: "3.9" + + # -- Mountpath where mount data + homePath: "/home/coder" + + # -- Configure args + #
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ + args: + - "-c" + - "trap : TERM INT; sleep infinity & wait" + + # -- Configure command + #
Ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/ + command: + - /bin/bash + + # -- Environment variables to configure application + env: {} + # AWS_ACCESS_KEY: "" + # AWS_SECRET_KEY: "" + # MINIO_ENDPOINT: "" + + # -- Variables from secrets + envFromSecrets: {} + # MY_VARIABLE: + # name: + # key: secret_key + + # -- Variables from configMap + envFromConfigMap: {} + # MY_VARIABLE: + # name: + # key: key + + # -- Load all variables from files + #
Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables + envFromFiles: [] + # - secretRef: + # name: + # - configMapRef: + # name: + + # -- Additional volumeMounts on the output Deployment definition + volumeMounts: [] + # - name: foo + # mountPath: "/etc/foo" + # readOnly: true + + # -- Configure lifecycle hooks + #
Ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ + #
Ref: https://learnk8s.io/graceful-shutdown + lifecycle: {} + # preStop: + # exec: + # command: ["sh", "-c", "sleep 10"] + # postStart: + # exec: + # command: + # - "/bin/sh" + # - "-c" + # - "ssh-keyscan -H keycloak >> /app/.ssh/known_hosts" + + # -- Resources limits and requested + #
Ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi diff --git a/user-tools-operator/helm-charts/usertools/Chart.yaml b/user-tools-operator/helm-charts/usertools/Chart.yaml deleted file mode 100644 index 434ab0464..000000000 --- a/user-tools-operator/helm-charts/usertools/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: user-tools -version: 0.1.0 diff --git a/user-tools-operator/helm-charts/usertools/templates/_helpers.tpl b/user-tools-operator/helm-charts/usertools/templates/_helpers.tpl deleted file mode 100644 index 347d8cd3c..000000000 --- a/user-tools-operator/helm-charts/usertools/templates/_helpers.tpl +++ /dev/null @@ -1,74 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "user-tools.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "user-tools.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "user-tools.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "user-tools.labels" -}} -app.kubernetes.io/name: {{ include "user-tools.name" . }} -helm.sh/chart: {{ include "user-tools.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "user-tools.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} -{{ default (include "user-tools.fullname" .) .Values.serviceAccount.name }} -{{- else -}} -{{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} - -{{/* -Add the protocol part to the uri -*/}} -{{- define "protocol" -}} -{{ ternary "https" "http" .Values.tls.enabled }} -{{- end -}} - -{{/* -Create user-tools tls secret name -*/}} -{{- define "user-tools.tlsSecretName" -}} -{{- if hasKey .Values.tls "secretName" -}} - {{- .Values.tls.secretName -}} -{{- else -}} - {{- printf "%s-tls" (include "user-tools.fullname" .) -}} -{{- end -}} -{{- end -}} diff --git a/user-tools-operator/helm-charts/usertools/templates/code-service.yaml b/user-tools-operator/helm-charts/usertools/templates/code-service.yaml deleted file mode 100644 index 437b7105e..000000000 --- a/user-tools-operator/helm-charts/usertools/templates/code-service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if .Values.vscode.enabled }} - -apiVersion: v1 -kind: Service -metadata: - name: {{ include "user-tools.fullname" . }}-code - labels: -{{ include "user-tools.labels" . | indent 4 }} -spec: - clusterIP: None - ports: - - port: 80 - targetPort: 4180 - protocol: TCP - name: http - selector: - app.kubernetes.io/name: {{ include "user-tools.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - -{{- end }} diff --git a/user-tools-operator/helm-charts/usertools/templates/ingress.yaml b/user-tools-operator/helm-charts/usertools/templates/ingress.yaml deleted file mode 100644 index afe1921c4..000000000 --- a/user-tools-operator/helm-charts/usertools/templates/ingress.yaml +++ /dev/null @@ -1,48 +0,0 @@ -{{- if .Values.vscode.enabled }} - -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ include "user-tools.fullname" . }} - labels: -{{ include "user-tools.labels" . | indent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if .Values.ingress.className }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.tls.enabled }} - tls: - - hosts: - - {{ .Values.usernameSlug }}-code.{{ .Values.domain }} - secretName: {{ include "user-tools.tlsSecretName" . }} - {{- end }} - rules: - - host: {{ .Values.usernameSlug }}-code.{{ .Values.domain }} - http: - paths: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress" }} - - pathType: Prefix - path: "/" - backend: - service: - name: {{ include "user-tools.fullname" . }}-code - port: - number: 80 - {{- else }} - - path: / - backend: - serviceName: {{ include "user-tools.fullname" . }}-code - servicePort: http - {{- end }} - -{{- end }} diff --git a/user-tools-operator/helm-charts/usertools/templates/rbac.yaml b/user-tools-operator/helm-charts/usertools/templates/rbac.yaml deleted file mode 100644 index d52241dc7..000000000 --- a/user-tools-operator/helm-charts/usertools/templates/rbac.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: user-tools-{{ .Values.usernameSlug }} -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - list -- apiGroups: - - "" - resources: - - pods/exec - resourceNames: - - "{{ include "user-tools.fullname" . }}-0" - verbs: - - create -- apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - create - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: user-tools-{{ .Values.usernameSlug }} -subjects: -- kind: ServiceAccount - name: {{ .Values.serviceAccountName }} -roleRef: - kind: Role - name: user-tools-{{ .Values.usernameSlug }} - apiGroup: rbac.authorization.k8s.io diff --git a/user-tools-operator/helm-charts/usertools/templates/statefulset.yaml b/user-tools-operator/helm-charts/usertools/templates/statefulset.yaml deleted file mode 100644 index da084a615..000000000 --- a/user-tools-operator/helm-charts/usertools/templates/statefulset.yaml +++ /dev/null @@ -1,211 +0,0 @@ -{{ if .Capabilities.APIVersions.Has "apps/v1" }} -apiVersion: apps/v1 -{{ else if .Capabilities.APIVersions.Has "apps/v1beta1" }} -apiVersion: apps/v1beta1 -{{ end }} -kind: StatefulSet -metadata: - name: {{ include "user-tools.fullname" . }} - labels: -{{ include "user-tools.labels" . | indent 4 }} -spec: - serviceName: {{ include "user-tools.fullname" . }} - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: {{ include "user-tools.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - template: - metadata: - labels: - app.kubernetes.io/name: {{ include "user-tools.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app: user-tools-{{ .Values.usernameSlug }} - runtimeId: {{ .Values.vscodeRuntime.runtimeId }} - capabilityId: {{ .Values.vscodeRuntime.capabilityId }} - spec: - {{- with .Values.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - serviceAccountName: {{ .Values.serviceAccountName }} - securityContext: - fsGroup: 1000 - initContainers: - - name: create-kubeconfig - image: alpine/k8s:1.20.7 - imagePullPolicy: IfNotPresent - command: - - sh - - /generate-kubeconfig.sh - volumeMounts: - - name: user-pvc - mountPath: /home/coder - - name: kubeconfig-tpl-configmap - mountPath: /kubeconfig.tpl - subPath: kubeconfig.tpl - - name: kubeconfig-tpl-configmap - mountPath: /generate-kubeconfig.sh - subPath: generate-kubeconfig.sh - - name: create-ssh-folder - image: alpine:3.10 - imagePullPolicy: IfNotPresent - command: - - sh - - -c - - mkdir -p /home/kdl/.ssh && chown 1000:1000 /home/kdl/.ssh - volumeMounts: - - name: user-pvc - mountPath: /home/kdl - containers: - - name: {{ .Chart.Name }}-repo-cloner - image: {{ .Values.repoCloner.image.repository }}:{{ .Values.repoCloner.image.tag }} - imagePullPolicy: {{ .Values.repoCloner.image.pullPolicy }} - env: - - name: KDL_USER_NAME - value: "{{ .Values.username }}" - - name: KDL_SERVER_MONGODB_URI - value: "{{ .Values.repoCloner.mongodbURI }}" - volumeMounts: - - name: user-pvc - mountPath: /home/kdl - - name: {{ .Values.usernameSlug }}-ssh-keys-vol - mountPath: /home/kdl/.ssh/id_rsa - subPath: id_rsa - readOnly: true - {{- if .Values.vscode.enabled }} - - name: {{ .Chart.Name }}-vscode - image: {{ .Values.vscode.image.repository }}:{{ .Values.vscode.image.tag }} - imagePullPolicy: {{ .Values.vscode.image.pullPolicy }} - volumeMounts: - - name: user-pvc - mountPath: /home/coder - {{- if .Values.sharedVolume.name }} - - name: {{ .Values.sharedVolume.name }} - mountPath: /home/coder/shared-storage - readOnly: false - {{- end }} - - name: {{ .Values.usernameSlug }}-ssh-keys-vol - mountPath: /home/coder/.ssh/id_rsa - subPath: id_rsa - readOnly: true - {{- end }} - - name: {{ .Chart.Name }}-vscode-runtime - image: {{ .Values.vscodeRuntime.image.repository }}:{{ .Values.vscodeRuntime.image.tag }} - imagePullPolicy: {{ .Values.vscodeRuntime.image.pullPolicy }} - command: - - "/bin/bash" - args: - - "-c" - - "trap : TERM INT; sleep infinity & wait" - env: - - name: MINIO_ACCESS_KEY - valueFrom: - secretKeyRef: - name: kdl-server - key: MINIO_ACCESS_KEY - - name: MINIO_SECRET_KEY - valueFrom: - secretKeyRef: - name: kdl-server - key: MINIO_SECRET_KEY - - name: MINIO_ENDPOINT - valueFrom: - secretKeyRef: - name: kdl-server - key: MINIO_ENDPOINT - - name: MC_HOST_dell - value: "http://$(MINIO_ACCESS_KEY):$(MINIO_SECRET_KEY)@$(MINIO_ENDPOINT)" - volumeMounts: - - name: user-pvc - mountPath: /home/coder - {{- if .Values.sharedVolume.name }} - - name: {{ .Values.sharedVolume.name }} - mountPath: /home/coder/shared-storage - readOnly: false - {{- end }} - - name: {{ .Values.usernameSlug }}-ssh-keys-vol - mountPath: /home/coder/.ssh/id_rsa - subPath: id_rsa - readOnly: true - {{- if .Values.vscode.enabled }} - - name: {{ .Chart.Name }}-vscode-proxy - image: {{ .Values.oauth2Proxy.image.repository }}:{{ .Values.oauth2Proxy.image.tag }} - imagePullPolicy: {{ .Values.oauth2Proxy.image.pullPolicy }} - args: - - "--config=/etc/oauth2_proxy.cfg" - - "--email-domain=*" - - "--redirect-url={{ printf "%s://%s-code.%s/oauth2/callback" ( include "protocol" . ) .Values.usernameSlug .Values.domain }}" - - "--upstream=http://127.0.0.1:8080/" - - "--pass-user-headers=true" - - "--set-xauthrequest=true" - - "--skip-provider-button=true" - env: - - name: OAUTH2_PROXY_HTTP_ADDRESS - value: "0.0.0.0:4180" - - name: OAUTH2_PROXY_CLIENT_ID - valueFrom: - secretKeyRef: - name: codeserver-oauth2-credentials-{{ .Values.usernameSlug }} - key: OAUTH2_CLIENT_ID - - name: OAUTH2_PROXY_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: codeserver-oauth2-credentials-{{ .Values.usernameSlug }} - key: OAUTH2_CLIENT_SECRET - volumeMounts: - - name: oauth2-config - mountPath: /etc/oauth2_proxy.cfg - subPath: oauth2_proxy.cfg - ports: - - name: http - containerPort: 4180 - protocol: TCP - {{- end }} - volumes: - - name: kubeconfig-tpl-configmap - configMap: - name: kubeconfig-{{ .Values.usernameSlug }}-tpl-configmap - {{- if .Values.vscode.enabled }} - - name: oauth2-config - configMap: - name: {{ include "user-tools.fullname" . }}-oauth2-proxy - {{- end }} - {{ if .Values.sharedVolume.name -}} - - name: {{ .Values.sharedVolume.name }} - persistentVolumeClaim: - claimName: {{ .Values.sharedVolume.name }}-claim - readOnly: false - {{- end }} - - name: {{ .Values.usernameSlug }}-ssh-keys-vol - secret: - secretName: {{ .Values.usernameSlug }}-ssh-keys - items: - - key: KDL_USER_PRIVATE_SSH_KEY - path: id_rsa - - name: {{ .Values.usernameSlug }}-ssh-pub - secret: - secretName: {{ .Values.usernameSlug }}-ssh-keys - items: - - key: KDL_USER_PUBLIC_SSH_KEY - path: authorized_keys - volumeClaimTemplates: - - metadata: - name: user-pvc - labels: - app: user - spec: - accessModes: - - ReadWriteOnce - storageClassName: {{ .Values.storage.className }} - resources: - requests: - storage: {{ .Values.storage.size }} diff --git a/user-tools-operator/helm-charts/usertools/values.yaml b/user-tools-operator/helm-charts/usertools/values.yaml deleted file mode 100644 index a669f1644..000000000 --- a/user-tools-operator/helm-charts/usertools/values.yaml +++ /dev/null @@ -1,85 +0,0 @@ -domain: kdl.local - -ingress: - className: "nginx" - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "1000000m" - nginx.ingress.kubernetes.io/configuration-snippet: | - more_set_headers "Content-Security-Policy: frame-ancestors 'self' *"; - -oauth2Proxy: - image: - repository: quay.io/oauth2-proxy/oauth2-proxy - tag: v7.7.1-amd64 - pullPolicy: IfNotPresent - -repoCloner: - image: - repository: konstellation/repo-cloner - tag: "latest" - pullPolicy: IfNotPresent - mongodbURI: "" - -sharedVolume: - name: "" - -storage: - size: 10Gi - className: standard - -tls: - enabled: false - - ## Custom TLS secret - ## Must be a valid wildcard certificate for the domain - ## declared in .Values.domain - ## Certificate name example: - ## *.example.com - # - # secretName: "" - -username: user.name - -usernameSlug: user-name - -## The service account for the user that owns the user-tools -serviceAccountName: default - -## If enabled, users will be able to download a kubeconfig file, so they can attach an external terminal/IDE to -## the vscodeRuntime running inside KST. -kubeconfig: - enabled: false - # enabled: true - - ## External cluster address to be able to connect to it from the outside. - # externalServerUrl: https://192.168.0.21:16443 - -vscode: - enabled: false - image: - repository: konstellation/vscode - tag: "latest" - pullPolicy: IfNotPresent - -vscodeRuntime: - runtimeId: "61383716a8c1d7ce4764f411" - capabilityId: "capability_id_1" - image: - repository: konstellation/kdl-py - tag: "3.9" - pullPolicy: Always - -## Define which Nodes the Pods are scheduled on. -## ref: https://kubernetes.io/docs/user-guide/node-selection/ -## -nodeSelector: {} - -## Assign custom affinity rules -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ -## -affinity: {} - -## If specified, the pod's tolerations. -## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -## -tolerations: [] diff --git a/user-tools-operator/watches.yaml b/user-tools-operator/watches.yaml index 7896085cb..d5dec35bf 100644 --- a/user-tools-operator/watches.yaml +++ b/user-tools-operator/watches.yaml @@ -1,5 +1,5 @@ --- -- version: v1alpha1 +- version: v1 group: kdl.konstellation.io - kind: UserTools - chart: helm-charts/usertools + kind: KDLUserTools + chart: helm-charts/kdl-user-tools