diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3f27492331..6af250d603 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: # Autoformat: markdown, yaml - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0 + rev: v3.0.3 hooks: - id: prettier @@ -53,7 +53,7 @@ repos: hooks: - id: sops-encryption # Add files here if they contain the word 'secret' but should not be encrypted - exclude: secrets\.md|helm-charts/support/templates/prometheus-ingres-auth/secret\.yaml|helm-charts/basehub/templates/dex/secret\.yaml|helm-charts/basehub/templates/static/secret\.yaml|config/clusters/templates/gcp/support\.secret\.values\.yaml|helm-charts/basehub/templates/ingress-auth/secret\.yaml + exclude: secrets\.md|helm-charts/support/templates/prometheus-ingres-auth/secret\.yaml|helm-charts/basehub/templates/dex/secret\.yaml|helm-charts/basehub/templates/static/secret\.yaml|config/clusters/templates/common/support\.secret\.values\.yaml|helm-charts/basehub/templates/ingress-auth/secret\.yaml # pre-commit.ci config reference: https://pre-commit.ci/#configuration ci: diff --git a/config/clusters/2i2c-aws-us/cosmicds.values.yaml b/config/clusters/2i2c-aws-us/cosmicds.values.yaml index b1c65618e3..77931e0b27 100644 --- a/config/clusters/2i2c-aws-us/cosmicds.values.yaml +++ b/config/clusters/2i2c-aws-us/cosmicds.values.yaml @@ -46,11 +46,33 @@ jupyterhub: type: none extraVolumeMounts: [] hub: + services: + # OAuth2 credentials for the CosmicDS portal, which uses + # this JupyterHub as authentication *provider*. So when users hit + # "Login" in the CosmicDS portal, they're actually redirected to this + # JupyterHub (via auth0). This ensures that the portal knows exactly + # the (anonymized) usernames of these users, and can do additional work + # on their part to track them as necessary. + cosmicds-portal: + # Don't display this service under 'services' in control panel + display: false + # Don't ask end user if they want to authorize this service explicitly + # This is a trusted service, and we are being used as *authentication* + # in this case. + oauth_no_confirm: true + name: cosmicds-portal + oauth_client_id: service-cosmicds-portal + # Callback URL for the auth0 tenant, provided to us by auth0 + oauth_redirect_uri: https://dev-tbr72rd5whnwlyrg.us.auth0.com/login/callback config: Authenticator: admin_users: - nmearl - patudom + # When using JupyterHub as an auth *provider*, we don't want the + # end user to see the JupyterHub home page at all - just redirect + # them to the upstream auth provider (CILogon) directly. + auto_login_oauth2_authorize: true JupyterHub: authenticator_class: cilogon CILogonOAuthenticator: @@ -60,20 +82,9 @@ jupyterhub: oauth_callback_url: https://cosmicds.2i2c.cloud/hub/oauth_callback shown_idps: - http://github.com/login/oauth/authorize - # Temporarily enable google & microsoft auth, to be reverted - # after July 21 2023 - # Ref https://github.com/2i2c-org/infrastructure/issues/2128#issuecomment-1633128941 - - http://google.com/accounts/o8/id - - http://login.microsoftonline.com/common/oauth2/v2.0/authorize allowed_idps: # The username claim here is used to do *authorization*, for both # admin use and any allow listing we want to do. http://github.com/login/oauth/authorize: username_derivation: username_claim: "preferred_username" - http://google.com/accounts/o8/id: - username_derivation: - username_claim: "email" - http://login.microsoftonline.com/common/oauth2/v2.0/authorize: - username_derivation: - username_claim: "email" diff --git a/config/clusters/2i2c-aws-us/enc-cosmicds.secret.values.yaml b/config/clusters/2i2c-aws-us/enc-cosmicds.secret.values.yaml index c47151ece0..6e1a46cc0b 100644 --- a/config/clusters/2i2c-aws-us/enc-cosmicds.secret.values.yaml +++ b/config/clusters/2i2c-aws-us/enc-cosmicds.secret.values.yaml @@ -1,22 +1,25 @@ jupyterhub: hub: + services: + cosmicds-portal: + api_token: ENC[AES256_GCM,data:QY4XnFjLgb8KqvVcXignYeJg7Xi5S5IWZ9dAFYy326XFo/oeds7DSDdj2rKam6zRX00ZC1+Cvx+FHlhL0FsjYg==,iv:dgw2az+wRJMt4uwklBcuxaYK64ETnKYH8VX0vS6RzRs=,tag:GP2yWFm9u69iUCogRoCkoQ==,type:str] extraEnv: - USERNAME_DERIVATION_PEPPER: ENC[AES256_GCM,data:AXMgK5+Gzojb2j65OA87X0BEs4JxjZr1jkemLRNhMp5pxdvt40YyMEO2fyhx+nfNwrvMf9DV6z9Hl7l2XEsbTQ==,iv:B9EBaac4VFOkU+nzxcm7LUzqJRJ4N38o4BbsZqxW69Q=,tag:cERvKEh9TfxyoDyzzVrb1Q==,type:str] + USERNAME_DERIVATION_PEPPER: ENC[AES256_GCM,data:mH/CtGOgBMPqUfy74r1sOdxxS2UcUAs/JkSItBgNKguTkV6WmBkd1VvEiRbiFmh86/VZrgFMj9k3B+eUfBSvMw==,iv:ZBhhx3mMrydErwPTNRQ391yUcZo4UIaEooz3exBY3c8=,tag:4eTclvSgvqby9qthqjAEcA==,type:str] config: CILogonOAuthenticator: - client_id: ENC[AES256_GCM,data:bG3o+fgg9Un2YzPxgBisMSpZ7mu0NnF3u7fbHFf3TErMRSNZdbKYne9InZfntOSt9CFP,iv:K+L30QknUdByGTTgs/Xo7xdWAl3ceUjyRi09PFFq0Us=,tag:GRtn+QCLaBjToj4Wk42kEg==,type:str] - client_secret: ENC[AES256_GCM,data:G/KW5Lha8iIEbK5nslLGyoM5wT/dokcGZN7cHd15QVdAExghviq1AtvqOIBDGH8O9QPU2YjJOfN+qCE3AGOAtuNFXHWevp5cwhrhD9aOsNqR1Qo4RrQ=,iv:losa6BtAz9dT4m7E3ANejNAJQt3ttKUdu21A00iErHU=,tag:QzBd1z3Qdc0DRDFsWTSZ5g==,type:str] + client_id: ENC[AES256_GCM,data:DSAp6gmFnGII9wyLwckBvljwqeokoiaOJdxs8DZdMGtAE68AB4ev5R+e5efCA3CpaFxr,iv:qo012XUuHmAlGbtyG8ty8HupB2GlZ7PLtAeD+9lvRIs=,tag:OU0VSIjWEJj9oh5N+IHwTg==,type:str] + client_secret: ENC[AES256_GCM,data:3NsIJWF/nUcXamPgXT4PQPhP8cBMXWSOHMXBZ9YRP/XC5wk34XgkGl3vKnVAD4XSLAsBHFWcPokojYkNvTx87gOhkCqXKt9lsjO0RB9xvyoGW6Pr+nk=,iv:9tKOZTcxBElSJvlMCdBk0Q76XNoSMd8RLMuEs07nXrE=,tag:ghWW2hqEBtwF+ZqPJNVl6Q==,type:str] sops: kms: [] gcp_kms: - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - created_at: "2023-07-12T23:25:29Z" - enc: CiUA4OM7eBXY4SwY7PqtCXIN7/imKKYLzyV95f+5/DHHbo5HCTWcEkkAyiwFHIvAzIjhSO3eQzb0EL6A6KW3ZEu2ZUp7s3PN8gOAy6HIcPbTLQrVnFlbMSAxDT8WShiikQDXHbyjFAKVzqo/KKMuEt9o + created_at: "2023-09-05T23:42:06Z" + enc: CiUA4OM7eEaWJ1qxGOi9/guRwEoX5kgrSadOZDGIBeCj6peMaRyOEkkAq2nhVZ+03d2/cJEMHW7xNpZPfjRhz/CKvKzJah09I7vJOSLmcnjbtagA605lm0SsKNsMZBPjRfAB7txSFOuAtn0Eh8B7JN/U azure_kv: [] hc_vault: [] age: [] - lastmodified: "2023-07-12T23:25:29Z" - mac: ENC[AES256_GCM,data:JOXoIfDhqmOeSCml+lTi56Sd5/8R36scNKTNP5Z3l1CqUJlm9Z3SBOitFWJ3uG78kNKnrYmtqc9ygbeKv3odBfx+IBRWwcp3kg+IGTxYcVzB1Ys+J0j2S0GzI7kPuEBYPuIuXxD1aAuJsolhyAjbS1S7ZqknFiyz+JCiqMMCLAY=,iv:C69JScxiP/XKWiUlu7AtMkf+s/EGnXKwmS8PrptDzZs=,tag:zxIWjO3Alas/uj5cJZqkbg==,type:str] + lastmodified: "2023-09-05T23:42:07Z" + mac: ENC[AES256_GCM,data:CAQeu301akd2ADKzfVg/l2cqJFpgq4DBLaxxnJP0meqVBEuOI8fOo/sBK0YcRWmF3skhQflsRLqDB+/a2jqoObGO0DJ8GgqH+0jY7KXoGllfYGpSEaa+gS3LBG0pERImY0w9+xc6RntmF9qz7JpN3zxQeLNkMY1FKaCD4jdZXwY=,iv:gEGI+YFnjH+GufdJI0U3kDzoNDW+6IAIHPLQFTcIAFE=,tag:UfXYOo61s9Qotn10fXhslQ==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3 diff --git a/config/clusters/2i2c-aws-us/enc-researchdelight.secret.values.yaml b/config/clusters/2i2c-aws-us/enc-researchdelight.secret.values.yaml index 3d2d84bd48..f69df82a9f 100644 --- a/config/clusters/2i2c-aws-us/enc-researchdelight.secret.values.yaml +++ b/config/clusters/2i2c-aws-us/enc-researchdelight.secret.values.yaml @@ -2,20 +2,23 @@ basehub: jupyterhub: hub: config: + GitHubOAuthenticator: + client_id: ENC[AES256_GCM,data:mBr82zqrB784x/9h2YpDiwPttzA=,iv:g9stn15R7RIl84NCVqzivpwrdX6MVFMulEJi3wHdCcw=,tag:V/BW6JCafJMbAAuaBWYkvg==,type:str] + client_secret: ENC[AES256_GCM,data:w5CT61Tu4UYraJcx64VJVweNYLjpS7PB8G0x1p8l3gKAnpBn6sX43g==,iv:P03azTpBmGrpt/ACXPtVs4fNarZfgcrjAxNFllrUsho=,tag:OF6BHKHd5GrHn5gQxVNi+A==,type:str] CILogonOAuthenticator: - client_id: ENC[AES256_GCM,data:do6oRsCHVlEaopw/SGKnudX6QMwTRo/Vco2sBCXkHNJ8aASBToFUlHqG8U8stmAe1eYJ,iv:FgtBzUzC8kap+BASyDY/sqnv1kvItTOX0a1j+mwYsy4=,tag:BhpZ5fAaYzSSIF9/RzLsXg==,type:str] - client_secret: ENC[AES256_GCM,data:1aIn9R5loffBYMuLuzn5+I+QkmX5qE7kYuqEKy0dvKJQZg/LK0yzVKoHiLOIYYJqTToVUMCc+aC+ZYTlNmCvGg3GwYPTkjVChRVYJRUZvl1ELP7YcV0=,iv:YORVpCcx9w4hgyKlomZKyAzEvnm+OFZbPu3tw3DvQAo=,tag:hUeV48uiv5PtjSp96o5n+w==,type:str] + client_id: ENC[AES256_GCM,data:kBmqvTcdnfTlPz2wNOp05Ck66COWMwvRCt7r6pfXLZnFr0v9ylxXwfDXT6v9YNiQ/do7,iv:c62ozJG3A53M37MFHbHINoYxtAwGMlh2y0oAsfuxh6c=,tag:vevTHn44TzlMpdOpSo5O3g==,type:str] + client_secret: ENC[AES256_GCM,data:G/tYPy+EV1HK5XdfTlBDAV/Ld383PQxI3zFwoFJLBKP6J4N211xvtb2AOcsuIfGqRb6o09wEk8QmJ43WoemOpffe3kqC5G5O/zAk9Fhm/5g4hN/PGeQ=,iv:G7uxbw7rqDkvulvPw0ZowgWS97RxHiTD7lbJ4yvgk/g=,tag:kZFlP7qWKC3VAdHokTxu3w==,type:str] sops: kms: [] gcp_kms: - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - created_at: "2023-03-13T10:27:13Z" - enc: CiUA4OM7eCdS0zudoyhLRbKlG+r1jUBQwFNAczMpasSH5X06+IWHEkkALQgViIkNihiV+Z+ZUwjJcCpuOprNMklD4AJ6UBeHxurj/VMPpCUBgveo7MwK/8+YMYofFpleS4b5rsLJ717oWDJjjM8cA8+W + created_at: "2023-09-09T02:50:00Z" + enc: CiUA4OM7eMBVcbO2oTRqg6XqINmiJiUqwFASA8+gT+IWQCiyCNdHEkkAq2nhVTfMsecT193wXiQYZZO034C3i8BL0wehQJzwvMlvu5r+PjYyIazgauyqQJxZQMvMIkO60/OcCzBEt0clYSj1tRFke98L azure_kv: [] hc_vault: [] age: [] - lastmodified: "2023-03-13T10:27:13Z" - mac: ENC[AES256_GCM,data:Bw1VoDnPAN1CvIOruB4SBVJf0gKXFbtOBHAy8gGSbA7s9PdiVN8FNmRSlutC8xKNqSVQ7vmtYhonJ+AHS6+PXa1aAceKMmQAmeMtwqE0HHSwR9Ujcw3F0bkjwHUMHIGgCOm0FawbHtMFBvAYXb8rgtCnZjGirJGmJ4TJ153IpXg=,iv:SsFQArAjuip3KyOvM45TsqHrNO0SQ+sTReuzZ5Yq8GU=,tag:TbqHDResuHQkapqPd9nSBA==,type:str] + lastmodified: "2023-09-09T02:50:00Z" + mac: ENC[AES256_GCM,data:zAVP82LEsEJo1KHKpNHm54uoPNCpQSyB6z1rRyztQ6g/hasEbS9VnC168/CKcx8tMqm25m8/gDu5WOiqZSeBnEmTqrAwSU2pa62A+zmwbORywto4b8BWgNR2Weoc7fD9Azfk4YHdQF/mQszXF207mP41z0yfF7vI7K6mgjZKKM8=,iv:V2OrjCuzY6H8RDOZp4JCFj9xCTF3dpUTpCGfbyYlXZs=,tag:YE8riKjxViXR/QIDATz+gw==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3 diff --git a/config/clusters/2i2c-aws-us/itcoocean.values.yaml b/config/clusters/2i2c-aws-us/itcoocean.values.yaml index a800c7ab78..7a9c19ae54 100644 --- a/config/clusters/2i2c-aws-us/itcoocean.values.yaml +++ b/config/clusters/2i2c-aws-us/itcoocean.values.yaml @@ -102,6 +102,11 @@ jupyterhub: # 16 CPU node: 0.9375 # 64 CPU node: 0.984375 # + # - Memory limits are setup conservatively to protect users from + # acquiring a false belief that what memory request they have made + # has been sufficient. This helps users tune their resource + # requests before events. + # - display_name: "Small: up to 4 CPU / 32 GB RAM" description: &profile_list_description "Start a container with at least a chosen share of capacity on a node of this type" slug: small @@ -113,11 +118,15 @@ jupyterhub: geospatial-python-tensorflow: display_name: Geospatial Python with tensorflow kubespawner_override: - image: eeholmes/iopython:20230714 + image: eeholmes/iopython-tf:20230901 + geospatial-python-openscapes: + display_name: Openscapes Python + kubespawner_override: + image: openscapes/python:f577786 geospatial-python-normal: display_name: Geospatial Python kubespawner_override: - image: openscapes/python:f577786 + image: eeholmes/iopython:20230901 geospatial-r-normal: display_name: Geospatial R kubespawner_override: @@ -126,7 +135,7 @@ jupyterhub: default: true display_name: Geospatial R with SDM kubespawner_override: - image: eeholmes/iorocker:20230714 + image: eeholmes/iorocker:20230901 requests: # NOTE: Node share choices are in active development, see comment # next to profileList: above. @@ -137,31 +146,37 @@ jupyterhub: display_name: ~1 GB, ~0.125 CPU kubespawner_override: mem_guarantee: 0.836G + mem_limit: 1G cpu_guarantee: 0.094 mem_2: display_name: ~2 GB, ~0.25 CPU kubespawner_override: mem_guarantee: 1.671G + mem_limit: 2G cpu_guarantee: 0.188 mem_4: display_name: ~4 GB, ~0.5 CPU kubespawner_override: mem_guarantee: 3.342G + mem_limit: 4G cpu_guarantee: 0.375 mem_8: display_name: ~8 GB, ~1.0 CPU kubespawner_override: mem_guarantee: 6.684G + mem_limit: 8G cpu_guarantee: 0.75 mem_16: display_name: ~16 GB, ~2.0 CPU kubespawner_override: mem_guarantee: 13.369G + mem_limit: 16G cpu_guarantee: 1.5 mem_32: display_name: ~32 GB, ~4.0 CPU kubespawner_override: mem_guarantee: 26.738G + mem_limit: 32G cpu_guarantee: 3.0 kubespawner_override: cpu_limit: null @@ -182,42 +197,50 @@ jupyterhub: display_name: ~1 GB, ~0.125 CPU kubespawner_override: mem_guarantee: 0.903G + mem_limit: 1G cpu_guarantee: 0.117 mem_2: display_name: ~2 GB, ~0.25 CPU kubespawner_override: mem_guarantee: 1.805G + mem_limit: 2G cpu_guarantee: 0.234 mem_4: default: true display_name: ~4 GB, ~0.5 CPU kubespawner_override: mem_guarantee: 3.611G + mem_limit: 4G cpu_guarantee: 0.469 mem_8: display_name: ~8 GB, ~1.0 CPU kubespawner_override: mem_guarantee: 7.222G + mem_limit: 8G cpu_guarantee: 0.938 mem_16: display_name: ~16 GB, ~2.0 CPU kubespawner_override: mem_guarantee: 14.444G + mem_limit: 16G cpu_guarantee: 1.875 mem_32: display_name: ~32 GB, ~4.0 CPU kubespawner_override: mem_guarantee: 28.887G + mem_limit: 32G cpu_guarantee: 3.75 mem_64: display_name: ~64 GB, ~8.0 CPU kubespawner_override: mem_guarantee: 57.775G + mem_limit: 64G cpu_guarantee: 7.5 mem_128: display_name: ~128 GB, ~16.0 CPU kubespawner_override: mem_guarantee: 115.549G + mem_limit: 128G cpu_guarantee: 15.0 kubespawner_override: cpu_limit: null diff --git a/config/clusters/2i2c-aws-us/researchdelight.values.yaml b/config/clusters/2i2c-aws-us/researchdelight.values.yaml index 51b0adb2cf..c7163a272c 100644 --- a/config/clusters/2i2c-aws-us/researchdelight.values.yaml +++ b/config/clusters/2i2c-aws-us/researchdelight.values.yaml @@ -30,18 +30,19 @@ basehub: hub: image: name: quay.io/2i2c/unlisted-choice-experiment - tag: "0.0.1-0.dev.git.6801.h3f4f0c4a" + tag: "0.0.1-0.dev.git.6863.h406a3546" config: JupyterHub: - authenticator_class: cilogon - CILogonOAuthenticator: + authenticator_class: github + Authenticator: + enable_auth_state: true + GitHubOAuthenticator: + populate_teams_in_auth_state: true + allowed_organizations: + - 2i2c-org:hub-access-for-2i2c-staff + - 2i2c-org:research-delight-team scope: - - "profile" - username_claim: "preferred_username" - oauth_callback_url: "https://researchdelight.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize + - read:org singleuser: image: name: quay.io/2i2c/researchdelight-image @@ -49,6 +50,9 @@ basehub: profileList: - display_name: "Shared Small: 1-4 CPU, 8-32 GB" description: "A shared machine, the recommended option until you experience a limitation." + allowed_teams: &allowed_teams + - 2i2c-org:hub-access-for-2i2c-staff + - 2i2c-org:research-delight-team profile_options: &profile_options image: display_name: Image @@ -56,7 +60,7 @@ basehub: enabled: True display_name: "Custom image" validation_regex: "^.+:.+$" - validation_message: "Must be an image location, matching ^.+:.+$" + validation_message: "Must be a publicly available docker image, of form :" kubespawner_override: image: "{value}" choices: @@ -107,6 +111,7 @@ basehub: - display_name: "Small: 4 CPU, 32 GB" description: "A dedicated machine for you." profile_options: *profile_options + allowed_teams: *allowed_teams kubespawner_override: mem_guarantee: 28.937G cpu_guarantee: 0.4 @@ -117,6 +122,7 @@ basehub: - display_name: "Medium: 16 CPU, 128 GB" description: "A dedicated machine for you." profile_options: *profile_options + allowed_teams: *allowed_teams kubespawner_override: mem_guarantee: 120.513G cpu_guarantee: 1.6 @@ -127,6 +133,7 @@ basehub: - display_name: "Large: 64 CPU, 512 GB" description: "A dedicated machine for you" profile_options: *profile_options + allowed_teams: *allowed_teams kubespawner_override: mem_guarantee: 489.13G cpu_guarantee: 6.4 @@ -136,6 +143,9 @@ basehub: - display_name: NVIDIA Tesla T4, ~16 GB, ~4 CPUs slug: gpu + allowed_teams: + - 2i2c-org:hub-access-for-2i2c-staff + - 2i2c-org:research-delight-gpu-team description: "Start a container on a dedicated node with a GPU" profile_options: image: diff --git a/config/clusters/2i2c-uk/staging.values.yaml b/config/clusters/2i2c-uk/staging.values.yaml index ce675a453f..26778efe99 100644 --- a/config/clusters/2i2c-uk/staging.values.yaml +++ b/config/clusters/2i2c-uk/staging.values.yaml @@ -38,10 +38,12 @@ jupyterhub: JupyterHub: authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://staging.uk.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub shown_idps: - - http://github.com/login/oauth/authorize + - http://google.com/accounts/o8/id + allowed_idps: + http://google.com/accounts/o8/id: + username_derivation: + username_claim: "email" + allowed_domains: + - "2i2c.org" diff --git a/config/clusters/2i2c/aup.values.yaml b/config/clusters/2i2c/aup.values.yaml index 33ef6ca896..5165598e51 100644 --- a/config/clusters/2i2c/aup.values.yaml +++ b/config/clusters/2i2c/aup.values.yaml @@ -39,12 +39,18 @@ jupyterhub: CILogonOAuthenticator: scope: - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://aup.pilot.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub shown_idps: - http://github.com/login/oauth/authorize + allowed_idps: + http://github.com/login/oauth/authorize: + username_derivation: + username_claim: "preferred_username" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &aup_users - swalker - shaolintl diff --git a/config/clusters/2i2c/basehub-common.values.yaml b/config/clusters/2i2c/basehub-common.values.yaml index f6def81488..a3024d57c5 100644 --- a/config/clusters/2i2c/basehub-common.values.yaml +++ b/config/clusters/2i2c/basehub-common.values.yaml @@ -1,5 +1,7 @@ nfs: enabled: true + dirsizeReporter: + enabled: true pv: mountOptions: - soft diff --git a/config/clusters/2i2c/binder-staging.values.yaml b/config/clusters/2i2c/binder-staging.values.yaml index 14813bacca..ff4227152d 100644 --- a/config/clusters/2i2c/binder-staging.values.yaml +++ b/config/clusters/2i2c/binder-staging.values.yaml @@ -83,7 +83,6 @@ binderhub: - yuvipanda@2i2c.org CILogonOAuthenticator: oauth_callback_url: "https://binder-staging.hub.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id allowed_idps: diff --git a/config/clusters/2i2c/cluster.yaml b/config/clusters/2i2c/cluster.yaml index d883edbae5..e9327649fc 100644 --- a/config/clusters/2i2c/cluster.yaml +++ b/config/clusters/2i2c/cluster.yaml @@ -25,17 +25,6 @@ hubs: - basehub-common.values.yaml - staging.values.yaml - enc-staging.secret.values.yaml - - name: hackanexoplanet - display_name: "ESA Hack An Exoplanet" - domain: hackanexoplanet.2i2c.cloud - uptime_check: - # This is an ephemeral hub, fully password protected with HTTP Basic Auth - expected_status: 401 - helm_chart: basehub - helm_chart_values_files: - - basehub-common.values.yaml - - hackanexoplanet.values.yaml - - enc-hackanexoplanet.secret.values.yaml - name: dask-staging display_name: "2i2c dask staging" domain: dask-staging.2i2c.cloud @@ -75,14 +64,6 @@ hubs: - daskhub-common.values.yaml - ohw.values.yaml - enc-ohw.secret.values.yaml - - name: pfw - display_name: "Purdue Fort Wayne" - domain: pfw.pilot.2i2c.cloud - helm_chart: basehub - helm_chart_values_files: - - basehub-common.values.yaml - - pfw.values.yaml - - enc-pfw.secret.values.yaml - name: aup display_name: "The American University of Paris" domain: aup.pilot.2i2c.cloud diff --git a/config/clusters/2i2c/dask-staging.values.yaml b/config/clusters/2i2c/dask-staging.values.yaml index a8d141f398..0a0119ed56 100644 --- a/config/clusters/2i2c/dask-staging.values.yaml +++ b/config/clusters/2i2c/dask-staging.values.yaml @@ -48,16 +48,11 @@ basehub: - "email" - "profile" oauth_callback_url: "https://dask-staging.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://accounts.google.com/o/oauth2/auth - - http://github.com/login/oauth/authorize allowed_idps: http://google.com/accounts/o8/id: username_derivation: username_claim: "email" allowed_domains: - "2i2c.org" - http://github.com/login/oauth/authorize: - username_derivation: - username_claim: "preferred_username" diff --git a/config/clusters/2i2c/daskhub-common.values.yaml b/config/clusters/2i2c/daskhub-common.values.yaml index f4c07b56b4..8969c703fe 100644 --- a/config/clusters/2i2c/daskhub-common.values.yaml +++ b/config/clusters/2i2c/daskhub-common.values.yaml @@ -1,6 +1,8 @@ basehub: nfs: enabled: true + dirsizeReporter: + enabled: true pv: mountOptions: - soft diff --git a/config/clusters/2i2c/enc-hackanexoplanet.secret.values.yaml b/config/clusters/2i2c/enc-hackanexoplanet.secret.values.yaml deleted file mode 100644 index 4e8bcebc2f..0000000000 --- a/config/clusters/2i2c/enc-hackanexoplanet.secret.values.yaml +++ /dev/null @@ -1,17 +0,0 @@ -ingressBasicAuth: - username: ENC[AES256_GCM,data:+fdObg==,iv:To7zbg0l8BA5X3Zkzt+fGv7XjCLLJ/w1zutp+ymAjWc=,tag:+tnCMGXRCWwRKS/cg35HYg==,type:str] - password: ENC[AES256_GCM,data:7hJUGTnj9mGYRkx2l6nAJ+CE2ZYolh0bbQ==,iv:H+VhPe2clY0nf0jVWkn+Aex1ajw3PtN9F7rI7lXizvw=,tag:qlACDFz9NH/vNBNhXWmWiw==,type:str] -sops: - kms: [] - gcp_kms: - - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - created_at: "2023-04-03T17:57:41Z" - enc: CiUA4OM7eKpDYQzdRUnNgglLnwjcnCH53FPCvXfEaaVtDR8AweM2EkkALQgViEBA5o+hR5n1jm3tdE/McgBDG7oHB8KwGFjR85ciwFPNQfnFxs2WoeNEXqtpYD9vSpatVpQWLAPgfVa3X228kEC23SBw - azure_kv: [] - hc_vault: [] - age: [] - lastmodified: "2023-04-03T17:57:42Z" - mac: ENC[AES256_GCM,data:UUJo8cmYYzeMtGCT8QRoVsaIlsER6fIXKSJ4e/9TZiDhXCrl6zAO79p43Qh5ziPUIIKFyKmtlweGW73DlsHoq+MLpMS3AxN32TwXtZEt2PTTdupJlgoiDvva3p4TTp7gwImo1i7iaGXIQd+QYmg3o3jQ9R9CWR5ZMgcQ57fzl9o=,iv:Z3xF1sYjfA5wO2839JwdKPdC0q9My4ZlFDMhiEMWR8M=,tag:uaHNptRlD8P9q0TSShzfLQ==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.7.3 diff --git a/config/clusters/2i2c/enc-pfw.secret.values.yaml b/config/clusters/2i2c/enc-pfw.secret.values.yaml deleted file mode 100644 index 805f6e1159..0000000000 --- a/config/clusters/2i2c/enc-pfw.secret.values.yaml +++ /dev/null @@ -1,20 +0,0 @@ -jupyterhub: - hub: - config: - CILogonOAuthenticator: - client_id: ENC[AES256_GCM,data:4FSmYZ6OiQP1B+43wHlzO9VHMfJPKxfKxH6W/GBuAleyp7BFn91151dS6+YN/cSivwgC,iv:1KGdpRM47DUsGdrV8ZkUQuRV82oFXxiAV0UZijYJKXA=,tag:oj/lYmWMHOt7NpLCP6PN1g==,type:str] - client_secret: ENC[AES256_GCM,data:E3JiAxfB/8L1GXzvZxEK1PoX2ft67eDShKPSyqNQdbrUmUrzebuHaCObFP0Dfr8tFXBWPlvN3X7RXXt9VMeFxCV0q3MECmdKGLwlML1hWSlZKemDLNE=,iv:h9kkTzPExnn88UJS0sKsGfYikY/YqkR7CyixBVJtcr4=,tag:cfspCQuGmlRIRdkRCQfdbA==,type:str] -sops: - kms: [] - gcp_kms: - - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - created_at: "2023-03-09T11:21:27Z" - enc: CiUA4OM7eBjOaqEY18nDzOArcUN3ot6bWO6eRt6z/WMN+9dAcm45EkkALQgViD9hreey1Ktl+EPN5zr/WWA+P+BKx3LlQFT+kcqiIeAjFxYumbkgTtaQx659L22n0pMrtLRTptgK6pvasMM1lsVvduIt - azure_kv: [] - hc_vault: [] - age: [] - lastmodified: "2023-03-09T11:21:27Z" - mac: ENC[AES256_GCM,data:BPV9gmeCF/YZ5nUOgFEQrlBIPdSTgZ5UZF5ivBvTVF+8QjTfgkCf+CK+UnuHn7yKvUcTXulfnnLbt3AVbV1tPPPuLxDYJCLc4qql8lmChZSz6YUZ26dxo84Psl3S3VuzKohdsLW+6oXHeHVe4W1E5JEgvPHmRaaCUkvxojrSMfM=,iv:+2Wc7J9HiJijwNVpzsritSyPU7VoxafPj+8H+vUyQLQ=,tag:FDj64UXxSMBtlaABw8FoLg==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.7.3 diff --git a/config/clusters/2i2c/hackanexoplanet.values.yaml b/config/clusters/2i2c/hackanexoplanet.values.yaml deleted file mode 100644 index fcf51d5280..0000000000 --- a/config/clusters/2i2c/hackanexoplanet.values.yaml +++ /dev/null @@ -1,67 +0,0 @@ -ingressBasicAuth: - enabled: true - # Password and username in enc-hackanexoplanet.secret.values.yaml - -jupyterhub: - prePuller: - # Startup performance is important for this event, and so we use - # pre-puller to make sure the images are already present on the - # nodes. This means image *must* be set in config, and not the configurator. - # tmpauthenticator doesn't support admin access anyway, so images - # must be set in config regardless. - hook: - enabled: true - continuous: - enabled: true - ingress: - annotations: - # We protect our entire hub from cryptobros by putting it all - # behind a single shared basicauth - nginx.ingress.kubernetes.io/auth-type: basic - nginx.ingress.kubernetes.io/auth-secret: ingress-basic-auth - nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" - hosts: - - hackanexoplanet.2i2c.cloud - tls: - - secretName: https-auto-tls - hosts: - - hackanexoplanet.2i2c.cloud - custom: - homepage: - # tmpauthenticator does *not* show a home page by default, - # so these are not visible anywhere. But our schema requires we set - # them to strings, so we specify empty strings here. - templateVars: - org: - name: "" - url: "" - logo_url: "" - designed_by: - name: "" - url: "" - operated_by: - name: "" - url: "" - funded_by: - name: "" - url: "" - singleuser: - image: - # Image repository: https://github.com/2i2c-org/hackanexoplanet-env - name: quay.io/2i2c/hackanexoplanet-image - tag: "b6b891cb2b30" - initContainers: null - storage: - # No persistent storage should be kept to reduce any potential data - # retention & privacy issues. - type: none - extraVolumeMounts: null - hub: - config: - JupyterHub: - authenticator_class: tmpauthenticator.TmpAuthenticator - TmpAuthenticator: - # This allows users to go to the hub URL directly again to - # get a new server, instead of being plopped back into their - # older, existing user with a 'start server' button. - force_new_server: true diff --git a/config/clusters/2i2c/imagebuilding-demo.values.yaml b/config/clusters/2i2c/imagebuilding-demo.values.yaml index 53f34fb730..1a66adb59e 100644 --- a/config/clusters/2i2c/imagebuilding-demo.values.yaml +++ b/config/clusters/2i2c/imagebuilding-demo.values.yaml @@ -38,7 +38,7 @@ jupyterhub: enabled: True display_name: "Custom image" validation_regex: "^.+:.+$" - validation_message: "Must be a valid public docker image, including a tag" + validation_message: "Must be a publicly available docker image, of form :" kubespawner_override: image: "{value}" choices: @@ -58,18 +58,28 @@ jupyterhub: mem_limit: 2G cpu_limit: 2 hub: + services: + binder: + # FIXME: ref https://github.com/2i2c-org/binderhub-service/issues/57 + # for something more readable and requiring less copy-pasting + url: http://imagebuilding-demo-binderhub-service:8090 image: name: quay.io/2i2c/dynamic-image-building-experiment - tag: "0.0.1-0.dev.git.6765.h33942a27" + tag: "0.0.1-0.dev.git.7001.hf02ed7a1" config: JupyterHub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://imagebuilding-demo.2i2c.cloud/hub/oauth_callback" - username_claim: "email" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id + allowed_idps: + http://google.com/accounts/o8/id: + username_derivation: + username_claim: "email" + allowed_domains: + - "2i2c.org" + extraConfig: enable-prototype-UI: | from kubespawner_dynamic_building_ui import TEMPLATE_PATHS, STATIC_HANDLER_TUPLE @@ -102,6 +112,7 @@ binderhub-service: effect: NoSchedule config: BinderHub: + base_url: /services/binder use_registry: true # Re-uses the registry created for the `binderhub-staging` hub # but pushes images under a different prefix diff --git a/config/clusters/2i2c/neurohackademy.values.yaml b/config/clusters/2i2c/neurohackademy.values.yaml index 9a492bca4a..f5fba70b7f 100644 --- a/config/clusters/2i2c/neurohackademy.values.yaml +++ b/config/clusters/2i2c/neurohackademy.values.yaml @@ -56,6 +56,10 @@ jupyterhub: JupyterHub: authenticator_class: cilogon Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &neurohackademy_users - arokem admin_users: *neurohackademy_users diff --git a/config/clusters/2i2c/pfw.values.yaml b/config/clusters/2i2c/pfw.values.yaml deleted file mode 100644 index 6418fa3ae3..0000000000 --- a/config/clusters/2i2c/pfw.values.yaml +++ /dev/null @@ -1,48 +0,0 @@ -jupyterhub: - ingress: - hosts: - - pfw.pilot.2i2c.cloud - tls: - - secretName: https-auto-tls - hosts: - - pfw.pilot.2i2c.cloud - custom: - 2i2c: - add_staff_user_ids_to_admin_users: true - add_staff_user_ids_of_type: "github" - homepage: - templateVars: - org: - name: Purdue Fort Wayne - logo_url: https://upload.wikimedia.org/wikipedia/en/thumb/1/14/Purdue_Fort_Wayne_Mastodons_logo.svg/400px-Purdue_Fort_Wayne_Mastodons_logo.svg.png - url: https://www.pfw.edu/ - designed_by: - name: 2i2c - url: https://2i2c.org - operated_by: - name: 2i2c - url: https://2i2c.org - funded_by: - name: JROST & IOI - url: https://investinopen.org/blog/jrost-rapid-response-fund-awardees - singleuser: - image: - name: quay.io/2i2c/2i2c-hubs-image - tag: "14107b8a85fb" - hub: - config: - JupyterHub: - authenticator_class: cilogon - CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" - oauth_callback_url: "https://pfw.pilot.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize - Authenticator: - allowed_users: &pfw_users - - alessandromariaselvitella - - fosterk86 - admin_users: *pfw_users diff --git a/config/clusters/2i2c/staging.values.yaml b/config/clusters/2i2c/staging.values.yaml index 633e51985b..bd95f724f0 100644 --- a/config/clusters/2i2c/staging.values.yaml +++ b/config/clusters/2i2c/staging.values.yaml @@ -56,7 +56,11 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://staging.2i2c.cloud/hub/oauth_callback" - username_claim: "email" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id + allowed_idps: + http://google.com/accounts/o8/id: + username_derivation: + username_claim: "email" + allowed_domains: + - "2i2c.org" diff --git a/config/clusters/2i2c/support.values.yaml b/config/clusters/2i2c/support.values.yaml index 6bd49d7968..10cb266142 100644 --- a/config/clusters/2i2c/support.values.yaml +++ b/config/clusters/2i2c/support.values.yaml @@ -1,11 +1,16 @@ prometheusIngressAuthSecret: enabled: true +prometheusStorageClass: + gke: + enabled: true + prometheus: server: persistentVolume: # 100Gi filled up, and this is source of our billing data. size: 512Gi + storageClass: balanced-rwo-retain ingress: enabled: true hosts: diff --git a/config/clusters/callysto/common.values.yaml b/config/clusters/callysto/common.values.yaml index 5e155812f6..045570e4f8 100644 --- a/config/clusters/callysto/common.values.yaml +++ b/config/clusters/callysto/common.values.yaml @@ -136,7 +136,6 @@ jupyterhub: - "102749090965437723445" # Byron Chu (Cybera) - "115909958579864751636" # Michael Jones (Cybera) - "106951135662332329542" # Elmar Bouwer (Cybera) - # Only show the option to login with Google and Mirosoft shown_idps: - https://accounts.google.com/o/oauth2/auth - https://login.microsoftonline.com/common/oauth2/v2.0/authorize diff --git a/config/clusters/carbonplan/common.values.yaml b/config/clusters/carbonplan/common.values.yaml index a984db5746..28a0dd8685 100644 --- a/config/clusters/carbonplan/common.values.yaml +++ b/config/clusters/carbonplan/common.values.yaml @@ -185,7 +185,22 @@ basehub: memory: 4Gi allowNamedServers: true config: + JupyterHub: + authenticator_class: cilogon + CILogonOAuthenticator: + scope: + - "profile" + shown_idps: + - http://github.com/login/oauth/authorize + allowed_idps: + http://github.com/login/oauth/authorize: + username_derivation: + username_claim: "preferred_username" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to + # be configured explicitly. + # allowed_users: &users - maxrjones admin_users: *users diff --git a/config/clusters/carbonplan/prod.values.yaml b/config/clusters/carbonplan/prod.values.yaml index 5dc1865e45..a8f4b3e428 100644 --- a/config/clusters/carbonplan/prod.values.yaml +++ b/config/clusters/carbonplan/prod.values.yaml @@ -7,13 +7,5 @@ basehub: secretName: https-auto-tls hub: config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://carbonplan.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/carbonplan/staging.values.yaml b/config/clusters/carbonplan/staging.values.yaml index b44c3c6fbd..64c03a33c2 100644 --- a/config/clusters/carbonplan/staging.values.yaml +++ b/config/clusters/carbonplan/staging.values.yaml @@ -7,13 +7,5 @@ basehub: secretName: https-auto-tls hub: config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://staging.carbonplan.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/catalystproject-latam/unitefa-conicet.values.yaml b/config/clusters/catalystproject-latam/unitefa-conicet.values.yaml index 5b45e8a68e..a2df37b761 100644 --- a/config/clusters/catalystproject-latam/unitefa-conicet.values.yaml +++ b/config/clusters/catalystproject-latam/unitefa-conicet.values.yaml @@ -33,8 +33,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://unitefa-conicet.latam.catalystproject.2i2c.cloud/hub/oauth_callback" - username_claim: "email" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id allowed_idps: diff --git a/config/clusters/cloudbank/ccsf.values.yaml b/config/clusters/cloudbank/ccsf.values.yaml index 2d21b692e4..eddea30343 100644 --- a/config/clusters/cloudbank/ccsf.values.yaml +++ b/config/clusters/cloudbank/ccsf.values.yaml @@ -35,7 +35,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://ccsf.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu diff --git a/config/clusters/cloudbank/elcamino.values.yaml b/config/clusters/cloudbank/elcamino.values.yaml index 585428d13e..c17106e95e 100644 --- a/config/clusters/cloudbank/elcamino.values.yaml +++ b/config/clusters/cloudbank/elcamino.values.yaml @@ -34,7 +34,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://elcamino.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu diff --git a/config/clusters/cloudbank/howard.values.yaml b/config/clusters/cloudbank/howard.values.yaml index 60403ebd39..47230603e2 100644 --- a/config/clusters/cloudbank/howard.values.yaml +++ b/config/clusters/cloudbank/howard.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://howard.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu @@ -41,6 +40,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &howard_users - ericvd@berkeley.edu - gwashington@scs.howard.edu diff --git a/config/clusters/cloudbank/lacc.values.yaml b/config/clusters/cloudbank/lacc.values.yaml index d7657fd83e..d0cfb85396 100644 --- a/config/clusters/cloudbank/lacc.values.yaml +++ b/config/clusters/cloudbank/lacc.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://lacc.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu @@ -41,6 +40,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &lacc_users - PINEDAEM@laccd.edu - LAMKT@laccd.edu diff --git a/config/clusters/cloudbank/mills.values.yaml b/config/clusters/cloudbank/mills.values.yaml index 86ccc7ee90..3ab1ed7d43 100644 --- a/config/clusters/cloudbank/mills.values.yaml +++ b/config/clusters/cloudbank/mills.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://datahub.mills.edu/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu diff --git a/config/clusters/cloudbank/miracosta.values.yaml b/config/clusters/cloudbank/miracosta.values.yaml index 4cb3cfeec4..571cf69625 100644 --- a/config/clusters/cloudbank/miracosta.values.yaml +++ b/config/clusters/cloudbank/miracosta.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: https://miracosta.cloudbank.2i2c.cloud/hub/oauth_callback - # Only show and allow option to login with Google and Miracosta institutional provider shown_idps: - http://google.com/accounts/o8/id - https://miracosta.fedgw.com/gateway diff --git a/config/clusters/cloudbank/mission.values.yaml b/config/clusters/cloudbank/mission.values.yaml index 5dd33723f5..16603ec4cf 100644 --- a/config/clusters/cloudbank/mission.values.yaml +++ b/config/clusters/cloudbank/mission.values.yaml @@ -35,7 +35,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: https://mission.cloudbank.2i2c.cloud/hub/oauth_callback - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu diff --git a/config/clusters/cloudbank/palomar.values.yaml b/config/clusters/cloudbank/palomar.values.yaml index c984cd9ce6..ed70944609 100644 --- a/config/clusters/cloudbank/palomar.values.yaml +++ b/config/clusters/cloudbank/palomar.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://palomar.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu @@ -41,6 +40,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &palomar_users - aculich@berkeley.edu - sean.smorris@berkeley.edu diff --git a/config/clusters/cloudbank/sbcc-dev.values.yaml b/config/clusters/cloudbank/sbcc-dev.values.yaml index a95946a67e..b9a5978e26 100644 --- a/config/clusters/cloudbank/sbcc-dev.values.yaml +++ b/config/clusters/cloudbank/sbcc-dev.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://sbcc-dev.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show and allow the option to login with Google shown_idps: - http://google.com/accounts/o8/id - https://idp.sbcc.edu/idp/shibboleth @@ -45,6 +44,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &sbcc_users - ericvd@gmail.com - sean.smorris@berkeley.edu diff --git a/config/clusters/cloudbank/sbcc.values.yaml b/config/clusters/cloudbank/sbcc.values.yaml index 48a8b1d6e5..bc6de536b7 100644 --- a/config/clusters/cloudbank/sbcc.values.yaml +++ b/config/clusters/cloudbank/sbcc.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://sbcc.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show and allow the option to login with Google shown_idps: - http://google.com/accounts/o8/id - https://idp.sbcc.edu/idp/shibboleth @@ -45,6 +44,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &sbcc_users - ericvd@gmail.com - sean.smorris@berkeley.edu diff --git a/config/clusters/cloudbank/sjsu.values.yaml b/config/clusters/cloudbank/sjsu.values.yaml index b2a7913321..eba295012f 100644 --- a/config/clusters/cloudbank/sjsu.values.yaml +++ b/config/clusters/cloudbank/sjsu.values.yaml @@ -38,7 +38,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: https://sjsu.cloudbank.2i2c.cloud/hub/oauth_callback - username_claim: "email" shown_idps: - http://google.com/accounts/o8/id - https://idp01.sjsu.edu/idp/shibboleth diff --git a/config/clusters/cloudbank/staging.values.yaml b/config/clusters/cloudbank/staging.values.yaml index b4ab54223a..3d2667584c 100644 --- a/config/clusters/cloudbank/staging.values.yaml +++ b/config/clusters/cloudbank/staging.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://staging.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show and allow the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu @@ -41,6 +40,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &staging_users - sean.smorris@berkeley.edu admin_users: *staging_users diff --git a/config/clusters/cloudbank/tuskegee.values.yaml b/config/clusters/cloudbank/tuskegee.values.yaml index 158149c164..6a2bd2b849 100644 --- a/config/clusters/cloudbank/tuskegee.values.yaml +++ b/config/clusters/cloudbank/tuskegee.values.yaml @@ -29,7 +29,6 @@ jupyterhub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://tuskegee.cloudbank.2i2c.cloud/hub/oauth_callback" - # Only show and allow the option to login with Google shown_idps: - http://google.com/accounts/o8/id - urn:mace:incommon:berkeley.edu @@ -41,6 +40,10 @@ jupyterhub: username_derivation: username_claim: "email" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &tuskegee_users - yasmeen.rawajfih@gmail.com - Wu.fan01@gmail.com diff --git a/config/clusters/gridsst/common.values.yaml b/config/clusters/gridsst/common.values.yaml index 9799545c71..718e911de3 100644 --- a/config/clusters/gridsst/common.values.yaml +++ b/config/clusters/gridsst/common.values.yaml @@ -37,6 +37,10 @@ basehub: hub: config: Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to + # be configured explicitly. + # allowed_users: &gridsst_users - alisonrgray - nikki-t diff --git a/config/clusters/jupyter-meets-the-earth/common.values.yaml b/config/clusters/jupyter-meets-the-earth/common.values.yaml index 1a15b5c014..ff8a41e278 100644 --- a/config/clusters/jupyter-meets-the-earth/common.values.yaml +++ b/config/clusters/jupyter-meets-the-earth/common.values.yaml @@ -224,11 +224,17 @@ basehub: CILogonOAuthenticator: scope: - "profile" - username_claim: "preferred_username" - # Only show the option to login with GitHub shown_idps: - http://github.com/login/oauth/authorize + allowed_idps: + http://github.com/login/oauth/authorize: + username_derivation: + username_claim: "preferred_username" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &users # This is just listing a few of the users/admins, a lot of # users has been added manually, see: diff --git a/config/clusters/leap/common.values.yaml b/config/clusters/leap/common.values.yaml index 12cf4b8ddd..bd4d000c24 100644 --- a/config/clusters/leap/common.values.yaml +++ b/config/clusters/leap/common.values.yaml @@ -39,7 +39,7 @@ basehub: hub: image: name: quay.io/2i2c/unlisted-choice-experiment - tag: "0.0.1-0.dev.git.6801.h3f4f0c4a" + tag: "0.0.1-0.dev.git.6863.h406a3546" allowNamedServers: true config: Authenticator: @@ -196,42 +196,26 @@ basehub: enabled: True display_name: "Custom image" validation_regex: "^.+:.+$" - validation_message: "Must be a valid public docker image, including a tag" + validation_message: "Must be a publicly available docker image, of form :" kubespawner_override: image: "{value}" choices: - pangeo_new: - display_name: Base Pangeo Notebook ("2023.07.05") - default: true - slug: "pangeo_new" - kubespawner_override: - image: "pangeo/pangeo-notebook:2023.07.05" pangeo: display_name: Base Pangeo Notebook default: true slug: "pangeo" kubespawner_override: - image: "pangeo/pangeo-notebook:ebeb9dd" - tensorflow_new: - display_name: Pangeo Tensorflow ML Notebook ("2023.07.05") - slug: "tensorflow_new" - kubespawner_override: - image: "pangeo/ml-notebook:2023.07.05" + image: "pangeo/pangeo-notebook:2023.08.29" tensorflow: display_name: Pangeo Tensorflow ML Notebook slug: "tensorflow" kubespawner_override: - image: "pangeo/ml-notebook:ebeb9dd" - pytorch_new: - display_name: Pangeo PyTorch ML Notebook ("2023.07.05") - slug: "pytorch_new" - kubespawner_override: - image: "pangeo/pytorch-notebook:2023.07.05" + image: "pangeo/ml-notebook:2023.08.29" pytorch: display_name: Pangeo PyTorch ML Notebook slug: "pytorch" kubespawner_override: - image: "pangeo/pytorch-notebook:ebeb9dd" + image: "pangeo/pytorch-notebook:2023.08.29" leap-pangeo-edu: display_name: LEAP Education Notebook (Testing Prototype) slug: "leap_edu" @@ -280,26 +264,16 @@ basehub: display_name: Image unlisted_choice: *profile_list_unlisted_choice choices: - tensorflow_new: - display_name: Pangeo Tensorflow ML Notebook ("2023.07.05") - slug: "tensorflow_new" - kubespawner_override: - image: "pangeo/ml-notebook:2023.07.05" tensorflow: display_name: Pangeo Tensorflow ML Notebook slug: "tensorflow" kubespawner_override: - image: "pangeo/ml-notebook:ebeb9dd" - pytorch_new: - display_name: Pangeo PyTorch ML Notebook ("2023.07.05") - slug: "pytorch_new" - kubespawner_override: - image: "pangeo/pytorch-notebook:2023.07.05" + image: "pangeo/ml-notebook:2023.08.29" pytorch: display_name: Pangeo PyTorch ML Notebook slug: "pytorch" kubespawner_override: - image: "pangeo/pytorch-notebook:ebeb9dd" + image: "pangeo/pytorch-notebook:2023.08.29" kubespawner_override: environment: NVIDIA_DRIVER_CAPABILITIES: compute,utility diff --git a/config/clusters/linked-earth/common.values.yaml b/config/clusters/linked-earth/common.values.yaml index f6c9068305..1354a071e2 100644 --- a/config/clusters/linked-earth/common.values.yaml +++ b/config/clusters/linked-earth/common.values.yaml @@ -109,7 +109,7 @@ basehub: cpu_limit: null mem_limit: null node_selector: - node.kubernetes.io/instance-type: e2-highmem-4 + node.kubernetes.io/instance-type: n2-highmem-4 - display_name: "Medium: up to 16 CPU / 128 GB RAM" description: *profile_list_description slug: medium @@ -165,7 +165,7 @@ basehub: cpu_limit: null mem_limit: null node_selector: - node.kubernetes.io/instance-type: e2-highmem-16 + node.kubernetes.io/instance-type: n2-highmem-16 dask-gateway: gateway: backend: diff --git a/config/clusters/meom-ige/cluster.yaml b/config/clusters/meom-ige/cluster.yaml index aa3de07390..0641eb08f6 100644 --- a/config/clusters/meom-ige/cluster.yaml +++ b/config/clusters/meom-ige/cluster.yaml @@ -1,5 +1,5 @@ name: meom-ige -provider: gcp # https://console.cloud.google.com/kubernetes/clusters/details/us-central1-b/pangeo-hubs-cluster/nodes?project=columbia +provider: gcp # https://console.cloud.google.com/kubernetes/clusters/details/us-central1-b/meom-ige-cluster/details?authuser=3&project=meom-ige-cnrs gcp: key: enc-deployer-credentials.secret.json project: meom-ige-cnrs diff --git a/config/clusters/meom-ige/common.values.yaml b/config/clusters/meom-ige/common.values.yaml index 18f30f437f..801aed9ce5 100644 --- a/config/clusters/meom-ige/common.values.yaml +++ b/config/clusters/meom-ige/common.values.yaml @@ -9,7 +9,7 @@ basehub: - soft # We pick soft over hard, so NFS lockups don't lead to hung processes - retrans=2 - noresvport - serverIP: nfs-server-01 + serverIP: nfs-server-01.us-central1-b.c.meom-ige-cnrs.internal baseShareName: /export/home-01/homes/ jupyterhub: custom: @@ -41,6 +41,7 @@ basehub: # RAM on a node, not total node capacity - display_name: "Small" description: "~2 CPU, ~8G RAM" + default: true kubespawner_override: mem_limit: 8G mem_guarantee: 4G @@ -83,7 +84,22 @@ basehub: enabled: false hub: config: + JupyterHub: + authenticator_class: cilogon + CILogonOAuthenticator: + scope: + - "profile" + shown_idps: + - http://github.com/login/oauth/authorize + allowed_idps: + http://github.com/login/oauth/authorize: + username_derivation: + username_claim: "preferred_username" Authenticator: + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: &users - roxyboy - lesommer diff --git a/config/clusters/meom-ige/prod.values.yaml b/config/clusters/meom-ige/prod.values.yaml index 1997a4b214..16a1d3c997 100644 --- a/config/clusters/meom-ige/prod.values.yaml +++ b/config/clusters/meom-ige/prod.values.yaml @@ -10,13 +10,5 @@ basehub: secretName: https-auto-tls hub: config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://meom-ige.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/meom-ige/staging.values.yaml b/config/clusters/meom-ige/staging.values.yaml index c2201a0589..2be03a1d34 100644 --- a/config/clusters/meom-ige/staging.values.yaml +++ b/config/clusters/meom-ige/staging.values.yaml @@ -10,13 +10,5 @@ basehub: secretName: https-auto-tls hub: config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://staging.meom-ige.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/nasa-ghg/common.values.yaml b/config/clusters/nasa-ghg/common.values.yaml index a34f5b16c1..5dd38f8907 100644 --- a/config/clusters/nasa-ghg/common.values.yaml +++ b/config/clusters/nasa-ghg/common.values.yaml @@ -19,9 +19,9 @@ basehub: homepage: templateVars: org: - name: "NASA Green House Gases Center" - logo_url: https://raw.githubusercontent.com/US-GHG-Center/ghgc-docs/87204d4a4e5f29c335a8f905c73de551aabd4845/Logo/ghg-logo.svg - url: https://www.nasa.gov/emd/ghg + name: "U.S. Greenhouse Gas Center" + logo_url: https://raw.githubusercontent.com/US-GHG-Center/ghgc-docs/b818ba6fdd3c43ede04b110975bf39d248c40df6/Logo/ghg-logo.svg + url: https://ghg.center designed_by: name: "2i2c" url: https://2i2c.org @@ -29,8 +29,8 @@ basehub: name: "2i2c" url: https://2i2c.org funded_by: - name: "NASA" - url: https://www.earthdata.nasa.gov/esds + name: "U.S. Greenhouse Gas Center" + url: https://ghg.center hub: allowNamedServers: true config: diff --git a/config/clusters/nasa-ghg/prod.values.yaml b/config/clusters/nasa-ghg/prod.values.yaml index 3acc34eaad..f0444fcb98 100644 --- a/config/clusters/nasa-ghg/prod.values.yaml +++ b/config/clusters/nasa-ghg/prod.values.yaml @@ -8,6 +8,10 @@ basehub: tls: - hosts: [hub.ghg.center] secretName: https-auto-tls + custom: + homepage: + gitRepoBranch: "master" + gitRepoUrl: "https://github.com/US-GHG-Center/ghgc-hub-homepage" hub: config: GitHubOAuthenticator: diff --git a/config/clusters/nasa-ghg/staging.values.yaml b/config/clusters/nasa-ghg/staging.values.yaml index 88db107033..c0da76fc18 100644 --- a/config/clusters/nasa-ghg/staging.values.yaml +++ b/config/clusters/nasa-ghg/staging.values.yaml @@ -8,6 +8,10 @@ basehub: tls: - hosts: [staging.ghg.2i2c.cloud] secretName: https-auto-tls + custom: + homepage: + gitRepoBranch: "staging" + gitRepoUrl: "https://github.com/US-GHG-Center/ghgc-hub-homepage" hub: config: GitHubOAuthenticator: diff --git a/config/clusters/nasa-veda/common.values.yaml b/config/clusters/nasa-veda/common.values.yaml index df645f0042..b3df072149 100644 --- a/config/clusters/nasa-veda/common.values.yaml +++ b/config/clusters/nasa-veda/common.values.yaml @@ -32,6 +32,9 @@ basehub: name: "NASA" url: https://www.earthdata.nasa.gov/esds hub: + image: + name: quay.io/2i2c/unlisted-choice-experiment + tag: "0.0.1-0.dev.git.6863.h406a3546" allowNamedServers: true config: Authenticator: @@ -56,8 +59,8 @@ basehub: image: name: public.ecr.aws/nasa-veda/nasa-veda-singleuser # Based off pangeo/pangeo-notebook:2023.07.05 which uses JupyterLab <4, so jupyterlab-git and dask-dashboard work - # If updating this tag, also update it in the profile_options section below - tag: "b807c7efa97c8df9ca38779f7e59d09f889fde9299b0d19de80389cf6b064f90" + # If updating this tag, also update it in the `profile_options.image.options.pangeo.kubespawner_override.image`below + tag: "5068290376e8c3151d97a36ae6485bb7ff79650b94aecc93ffb2ea1b42d76460" profileList: # NOTE: About node sharing # @@ -79,13 +82,57 @@ basehub: profile_options: image: &image_options display_name: Image + unlisted_choice: + enabled: True + display_name: "Custom image" + validation_regex: "^.+:.+$" + validation_message: "Must be a publicly available docker image, of form :" + kubespawner_override: + image: "{value}" choices: pangeo: display_name: Modified Pangeo Notebook default: true slug: pangeo kubespawner_override: - image: public.ecr.aws/nasa-veda/nasa-veda-singleuser:b807c7efa97c8df9ca38779f7e59d09f889fde9299b0d19de80389cf6b064f90 + image: public.ecr.aws/nasa-veda/nasa-veda-singleuser:5068290376e8c3151d97a36ae6485bb7ff79650b94aecc93ffb2ea1b42d76460 + init_containers: + # Need to explicitly fix ownership here, as otherwise these directories will be owned + # by root on most NFS filesystems - neither EFS nor Google Filestore support anonuid + - name: volume-mount-ownership-fix + image: busybox + command: + [ + "sh", + "-c", + "id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared && ls -lhd /home/jovyan ", + ] + securityContext: + runAsUser: 0 + volumeMounts: + - name: home + mountPath: /home/jovyan + subPath: "{username}" + # mounted without readonly attribute here, + # so we can chown it appropriately + - name: home + mountPath: /home/jovyan/shared + subPath: _shared + # this container uses nbgitpuller to mount https://github.com/NASA-IMPACT/veda-docs/ for user pods + # image source: https://github.com/NASA-IMPACT/veda-jh-environments/tree/main/docker-images/base/nasa-veda-singleuser-init + - name: nasa-veda-singleuser-init + image: public.ecr.aws/nasa-veda/nasa-veda-singleuser-init:38e8998f9be64b0a59ac6c4d6d152d3403121dfc4be6d49bdf52ddc92827af8a + command: + - "python3" + - "/opt/k8s-init-container-nb-docs.py" + - "/home/jovyan" + volumeMounts: + - name: home + mountPath: /home/jovyan + subPath: "{username}" + securityContext: + runAsUser: 1000 + runAsGroup: 1000 rocker: display_name: Rocker Geospatial with RStudio slug: rocker @@ -107,6 +154,38 @@ basehub: mountPath: /home/rstudio/shared subPath: _shared readOnly: true + init_containers: + # Need to explicitly fix ownership here, as otherwise these directories will be owned + # by root on most NFS filesystems - neither EFS nor Google Filestore support anonuid + - name: volume-mount-ownership-fix + image: busybox + command: + [ + "sh", + "-c", + "id && chown 1000:1000 /home/rstudio && ls -lhd /home/rstudio ", + ] + securityContext: + runAsUser: 0 + volumeMounts: + - name: home + mountPath: /home/rstudio + subPath: "{username}" + # this container uses nbgitpuller to mount https://github.com/NASA-IMPACT/veda-docs/ for user pods + # image source: https://github.com/NASA-IMPACT/veda-jh-environments/tree/main/docker-images/base/nasa-veda-singleuser-init + - name: nasa-veda-singleuser-init + image: public.ecr.aws/nasa-veda/nasa-veda-singleuser-init:38e8998f9be64b0a59ac6c4d6d152d3403121dfc4be6d49bdf52ddc92827af8a + command: + - "python3" + - "/opt/k8s-init-container-nb-docs.py" + - "/home/rstudio" + volumeMounts: + - name: home + mountPath: /home/rstudio + subPath: "{username}" + securityContext: + runAsUser: 1000 + runAsGroup: 1000 requests: # NOTE: Node share choices are in active development, see comment # next to profileList: above. diff --git a/config/clusters/nasa-veda/support.values.yaml b/config/clusters/nasa-veda/support.values.yaml index 526e523d7e..e51536e776 100644 --- a/config/clusters/nasa-veda/support.values.yaml +++ b/config/clusters/nasa-veda/support.values.yaml @@ -32,3 +32,11 @@ prometheus: - secretName: prometheus-tls hosts: - prometheus.nasa-veda.2i2c.cloud + +redirects: + rules: + # nasa-veda was previously used in the domain name, but domains including + # nasa that doesn't end in .gov can get blocked so the name was reduced to + # just veda, see https://github.com/2i2c-org/infrastructure/issues/3029 + - from: staging.nasa-veda.2i2c.cloud + to: staging.veda.2i2c.cloud diff --git a/config/clusters/openscapes/common.values.yaml b/config/clusters/openscapes/common.values.yaml index 9d12dd21bb..cb4feca425 100644 --- a/config/clusters/openscapes/common.values.yaml +++ b/config/clusters/openscapes/common.values.yaml @@ -40,90 +40,6 @@ basehub: mountPath: /home/jovyan/shared subPath: _shared readOnly: false - profileList: - - display_name: Python - description: Python datascience environment - default: true - kubespawner_override: - image: openscapes/python:f577786 - profile_options: &profile_options - requests: - display_name: Resource Allocation - choices: - mem_1_9: - display_name: 1.9 GB RAM, upto 3.75 CPUs - kubespawner_override: - mem_guarantee: 1992701952 - mem_limit: 1992701952 - cpu_guarantee: 0.234375 - cpu_limit: 3.75 - node_selector: - node.kubernetes.io/instance-type: r5.xlarge - default: true - mem_3_7: - display_name: 3.7 GB RAM, upto 3.75 CPUs - kubespawner_override: - mem_guarantee: 3985403904 - mem_limit: 3985403904 - cpu_guarantee: 0.46875 - cpu_limit: 3.75 - node_selector: - node.kubernetes.io/instance-type: r5.xlarge - mem_7_4: - display_name: 7.4 GB RAM, upto 3.75 CPUs - kubespawner_override: - mem_guarantee: 7970807808 - mem_limit: 7970807808 - cpu_guarantee: 0.9375 - cpu_limit: 3.75 - node_selector: - node.kubernetes.io/instance-type: r5.xlarge - mem_14_8: - display_name: 14.8 GB RAM, upto 3.75 CPUs - kubespawner_override: - mem_guarantee: 15941615616 - mem_limit: 15941615616 - cpu_guarantee: 1.875 - cpu_limit: 3.75 - node_selector: - node.kubernetes.io/instance-type: r5.xlarge - mem_29_7: - display_name: 29.7 GB RAM, upto 3.75 CPUs - kubespawner_override: - mem_guarantee: 31883231232 - mem_limit: 31883231232 - cpu_guarantee: 3.75 - cpu_limit: 3.75 - node_selector: - node.kubernetes.io/instance-type: r5.xlarge - mem_60_6: - display_name: 60.6 GB RAM, upto 15.72 CPUs - kubespawner_override: - mem_guarantee: 65105797120 - mem_limit: 65105797120 - cpu_guarantee: 7.86 - cpu_limit: 15.72 - node_selector: - node.kubernetes.io/instance-type: r5.4xlarge - mem_121_3: - display_name: 121.3 GB RAM, upto 15.72 CPUs - kubespawner_override: - mem_guarantee: 130211594240 - mem_limit: 130211594240 - cpu_guarantee: 15.72 - cpu_limit: 15.72 - node_selector: - node.kubernetes.io/instance-type: r5.4xlarge - - display_name: R - description: R (with RStudio) + Python environment - kubespawner_override: - image: openscapes/rocker:a7596b5 - profile_options: *profile_options - - display_name: Matlab - description: Matlab environment - kubespawner_override: - image: openscapes/matlab:2023-06-29 - profile_options: *profile_options scheduling: userScheduler: enabled: true @@ -135,13 +51,27 @@ basehub: readinessProbe: enabled: false config: + JupyterHub: + authenticator_class: cilogon + CILogonOAuthenticator: + scope: + - "profile" + shown_idps: + - http://github.com/login/oauth/authorize + allowed_idps: + http://github.com/login/oauth/authorize: + username_derivation: + username_claim: "preferred_username" Authenticator: admin_users: &users - amfriesz - jules32 - erinmr - betolink - # Without this, any GitHub user can authenticate + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: *users dask-gateway: gateway: diff --git a/config/clusters/openscapes/prod.values.yaml b/config/clusters/openscapes/prod.values.yaml index 784e7bd9e7..a937472f8a 100644 --- a/config/clusters/openscapes/prod.values.yaml +++ b/config/clusters/openscapes/prod.values.yaml @@ -5,15 +5,92 @@ basehub: tls: - hosts: [openscapes.2i2c.cloud] secretName: https-auto-tls + singleuser: + profileList: + - display_name: Python + description: Python datascience environment + default: true + kubespawner_override: + image: openscapes/python:f577786 + profile_options: &profile_options + requests: + display_name: Resource Allocation + choices: + mem_1_9: + display_name: 1.9 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 1992701952 + mem_limit: 1992701952 + cpu_guarantee: 0.234375 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + default: true + mem_3_7: + display_name: 3.7 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 3985403904 + mem_limit: 3985403904 + cpu_guarantee: 0.46875 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_7_4: + display_name: 7.4 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 7970807808 + mem_limit: 7970807808 + cpu_guarantee: 0.9375 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_14_8: + display_name: 14.8 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 15941615616 + mem_limit: 15941615616 + cpu_guarantee: 1.875 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_29_7: + display_name: 29.7 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 31883231232 + mem_limit: 31883231232 + cpu_guarantee: 3.75 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_60_6: + display_name: 60.6 GB RAM, upto 15.72 CPUs + kubespawner_override: + mem_guarantee: 65105797120 + mem_limit: 65105797120 + cpu_guarantee: 7.86 + cpu_limit: 15.72 + node_selector: + node.kubernetes.io/instance-type: r5.4xlarge + mem_121_3: + display_name: 121.3 GB RAM, upto 15.72 CPUs + kubespawner_override: + mem_guarantee: 130211594240 + mem_limit: 130211594240 + cpu_guarantee: 15.72 + cpu_limit: 15.72 + node_selector: + node.kubernetes.io/instance-type: r5.4xlarge + - display_name: R + description: R (with RStudio) + Python environment + kubespawner_override: + image: openscapes/rocker:a7596b5 + profile_options: *profile_options + - display_name: Matlab + description: Matlab environment + kubespawner_override: + image: openscapes/matlab:2023-06-29 + profile_options: *profile_options hub: config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://openscapes.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/openscapes/staging.values.yaml b/config/clusters/openscapes/staging.values.yaml index 5857a41cb4..13fcfa7ec1 100644 --- a/config/clusters/openscapes/staging.values.yaml +++ b/config/clusters/openscapes/staging.values.yaml @@ -5,15 +5,124 @@ basehub: tls: - hosts: [staging.openscapes.2i2c.cloud] secretName: https-auto-tls + singleuser: + profileList: + - display_name: Python + description: Python datascience environment + default: true + profile_options: + image: + display_name: Image and Tag + unlisted_choice: &unlisted_choice + enabled: true + display_name: "Custom image" + validation_regex: "^.+:.+$" + validation_message: "Must be a publicly available docker image, of form :" + kubespawner_override: + image: "{value}" + choices: + default: + display_name: openscapes/python:06b0503 + default: true + kubespawner_override: + image: openscapes/python:06b0503 + requests: &requests_profile_options + display_name: Resource Allocation + choices: + mem_1_9: + display_name: 1.9 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 1992701952 + mem_limit: 1992701952 + cpu_guarantee: 0.234375 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + default: true + mem_3_7: + display_name: 3.7 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 3985403904 + mem_limit: 3985403904 + cpu_guarantee: 0.46875 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_7_4: + display_name: 7.4 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 7970807808 + mem_limit: 7970807808 + cpu_guarantee: 0.9375 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_14_8: + display_name: 14.8 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 15941615616 + mem_limit: 15941615616 + cpu_guarantee: 1.875 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_29_7: + display_name: 29.7 GB RAM, upto 3.75 CPUs + kubespawner_override: + mem_guarantee: 31883231232 + mem_limit: 31883231232 + cpu_guarantee: 3.75 + cpu_limit: 3.75 + node_selector: + node.kubernetes.io/instance-type: r5.xlarge + mem_60_6: + display_name: 60.6 GB RAM, upto 15.72 CPUs + kubespawner_override: + mem_guarantee: 65105797120 + mem_limit: 65105797120 + cpu_guarantee: 7.86 + cpu_limit: 15.72 + node_selector: + node.kubernetes.io/instance-type: r5.4xlarge + mem_121_3: + display_name: 121.3 GB RAM, upto 15.72 CPUs + kubespawner_override: + mem_guarantee: 130211594240 + mem_limit: 130211594240 + cpu_guarantee: 15.72 + cpu_limit: 15.72 + node_selector: + node.kubernetes.io/instance-type: r5.4xlarge + - display_name: R + description: R (with RStudio) + Python environment + profile_options: + image: + display_name: Image and Tag + unlisted_choice: *unlisted_choice + choices: + default: + display_name: openscapes/rocker:a7596b5 + default: true + kubespawner_override: + image: openscapes/rocker:a7596b5 + requests: *requests_profile_options + - display_name: Matlab + description: Matlab environment + profile_options: + image: + display_name: Image and Tag + unlisted_choice: *unlisted_choice + choices: + default: + display_name: openscapes/matlab:2023-06-29 + default: true + kubespawner_override: + image: openscapes/matlab:2023-06-29 + requests: *requests_profile_options hub: + image: + name: quay.io/2i2c/unlisted-choice-experiment + tag: "0.0.1-0.dev.git.6863.h406a3546" config: - JupyterHub: - authenticator_class: cilogon CILogonOAuthenticator: - scope: - - "profile" - username_claim: "preferred_username" oauth_callback_url: "https://staging.openscapes.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with GitHub - shown_idps: - - http://github.com/login/oauth/authorize diff --git a/config/clusters/pangeo-hubs/coessing.values.yaml b/config/clusters/pangeo-hubs/coessing.values.yaml index f7814d1110..5bdcffc433 100644 --- a/config/clusters/pangeo-hubs/coessing.values.yaml +++ b/config/clusters/pangeo-hubs/coessing.values.yaml @@ -37,6 +37,10 @@ basehub: Authenticator: admin_users: &admin_users - paigemar@umich.edu + # FIXME: In z2jh 3.0.0-beta.1, a truthy allowed_users implies + # allow_existing_users=True, while in z3jh 3.0.0 this needs to be + # configured explicitly. + # allowed_users: *admin_users # Delete any prior existing users in the db that don't pass username_pattern delete_invalid_users: true @@ -44,12 +48,9 @@ basehub: authenticator_class: cilogon CILogonOAuthenticator: oauth_callback_url: "https://coessing.2i2c.cloud/hub/oauth_callback" - # Only show the option to login with Google shown_idps: - https://accounts.google.com/o/oauth2/auth allowed_idps: - # CILogon still uses the old google oidc enpoint instead of the new one listed in `shown_idps`. - # Ref https://github.com/ncsa/OA4MP/issues/45 http://google.com/accounts/o8/id: username_derivation: username_claim: "email" diff --git a/config/clusters/smithsonian/common.values.yaml b/config/clusters/smithsonian/common.values.yaml index 18b1e3c669..499066f1ff 100644 --- a/config/clusters/smithsonian/common.values.yaml +++ b/config/clusters/smithsonian/common.values.yaml @@ -38,7 +38,8 @@ basehub: JupyterHub: authenticator_class: github GitHubOAuthenticator: - allowed_organizations: + populate_teams_in_auth_state: true + allowed_organizations: &allowed_github_orgs - 2i2c-org - smithsonian - sidatasciencelab @@ -46,6 +47,7 @@ basehub: scope: - read:org Authenticator: + enable_auth_state: true # This hub uses GitHub Orgs auth and so we don't set allowed_users in # order to not deny access to valid members of the listed orgs. These # people should have admin access though. @@ -59,18 +61,6 @@ basehub: enabled: true singleuser: - image: - # Pending information about what image to use in - # https://github.com/2i2c-org/infrastructure/issues/2323, the - # pangeo/pangeo-notebook image was setup initially as it includes recent - # versions of dask/distributed which is relevant for a use with - # dask-gateway. - # - # image source: https://github.com/pangeo-data/pangeo-docker-images - # image published: https://quay.io/repository/pangeo/pangeo-notebook?tab=tags - # - name: quay.io/pangeo/pangeo-notebook - tag: "2023.02.27" profileList: # NOTE: About node sharing # @@ -89,6 +79,7 @@ basehub: description: &profile_list_description "Start a container with at least a chosen share of capacity on a node of this type" slug: small default: true + allowed_teams: *allowed_github_orgs profile_options: image: &profile_options_image display_name: Image @@ -113,12 +104,22 @@ basehub: display_name: Jupyter SciPy Notebook slug: scipy kubespawner_override: - image: jupyter/scipy-notebook:2023-06-26 + image: "jupyter/scipy-notebook:2023-09-04" pangeo: display_name: Pangeo Notebook slug: pangeo kubespawner_override: - image: quay.io/pangeo/pangeo-notebook:2023.02.27 + image: "quay.io/pangeo/pangeo-notebook:2023.08.29" + tensorflow: &image_tensorflow + display_name: Pangeo Tensorflow ML Notebook + slug: tensorflow + kubespawner_override: + image: "pangeo/ml-notebook:2023.08.29" + pytorch: &image_pytorch + display_name: Pangeo PyTorch ML Notebook + slug: pytorch + kubespawner_override: + image: "pangeo/pytorch-notebook:2023.08.29" requests: # NOTE: Node share choices are in active development, see comment # next to profileList: above. @@ -160,3 +161,25 @@ basehub: mem_limit: null node_selector: node.kubernetes.io/instance-type: r5.xlarge + + - display_name: NVIDIA Tesla T4, ~16 GB, ~4 CPUs + slug: gpu + description: "Start a container on a dedicated node with a GPU" + allowed_teams: + - 2i2c-org:hub-access-for-2i2c-staff + - Smithsonian-SDCH:gpu-users + profile_options: + image: + display_name: Image + choices: + tensorflow: *image_tensorflow + pytorch: *image_pytorch + kubespawner_override: + mem_limit: null + environment: + NVIDIA_DRIVER_CAPABILITIES: compute,utility + mem_guarantee: 14G + node_selector: + node.kubernetes.io/instance-type: g4dn.xlarge + extra_resource_limits: + nvidia.com/gpu: "1" diff --git a/config/clusters/templates/gcp/support.secret.values.yaml b/config/clusters/templates/common/support.secret.values.yaml similarity index 100% rename from config/clusters/templates/gcp/support.secret.values.yaml rename to config/clusters/templates/common/support.secret.values.yaml diff --git a/config/clusters/templates/gcp/support.values.yaml b/config/clusters/templates/common/support.values.yaml similarity index 100% rename from config/clusters/templates/gcp/support.values.yaml rename to config/clusters/templates/common/support.values.yaml diff --git a/config/clusters/ubc-eoas/common.values.yaml b/config/clusters/ubc-eoas/common.values.yaml index 17a34761be..fbbbf9ec92 100644 --- a/config/clusters/ubc-eoas/common.values.yaml +++ b/config/clusters/ubc-eoas/common.values.yaml @@ -36,80 +36,51 @@ jupyterhub: config: Authenticator: admin_users: - - ckrzysik # Primary technical representative, Charles Krzysik - - lheagy # Secondary technical representative, Lindsey Heagy + - ckrzysik # Technical representative, Charles Krzysik + - lheagy # Technical representative, Lindsey Heagy + - hmodzelewski # Technical representative, Henryk Modzelewski JupyterHub: authenticator_class: cilogon CILogonOAuthenticator: + shown_idps: + - https://authentication.ubc.ca + - http://google.com/accounts/o8/id allowed_idps: https://authentication.ubc.ca: username_derivation: username_claim: email action: strip_idp_domain domain: eoas.ubc.ca - allowed_domains: - - eoas.ubc.ca http://google.com/accounts/o8/id: username_derivation: username_claim: email allowed_domains: - 2i2c.org - shown_idps: - - https://authentication.ubc.ca - - http://google.com/accounts/o8/id singleuser: defaultUrl: /lab profileList: - - display_name: "Small: m5.large" - description: "~2 CPU, ~8G RAM" + - display_name: EOSC211 + description: "For class EOSC211, provides ~2 CPU and ~8G RAM" default: true - profile_options: &profile_options - environment: - display_name: Environment - choices: - eosc211: - display_name: EOSC211 - kubespawner_override: - # Using 'latest' for now so updates do not require 2i2c - # involvement. - image: quay.io/henrykmodzelewski/2i2c-eosc211:latest - eosc350: - display_name: EOSC350 - kubespawner_override: - # Using 'latest' for now so updates do not require 2i2c - # involvement. - image: quay.io/henrykmodzelewski/2i2c-eosc350:latest kubespawner_override: mem_limit: 8G mem_guarantee: 6.5G node_selector: node.kubernetes.io/instance-type: m5.large - - display_name: "Medium: m5.xlarge" - description: "~4 CPU, ~15G RAM" - profile_options: *profile_options + # Using 'latest' for now so updates do not require 2i2c + # involvement. + image: quay.io/henrykmodzelewski/2i2c-eosc211:latest + - display_name: EOSC350 + description: "For class EOSC350, provides ~2 CPU and ~8G RAM" kubespawner_override: - mem_limit: 15G - mem_guarantee: 12G - node_selector: - node.kubernetes.io/instance-type: m5.xlarge - - display_name: "Large: m5.2xlarge" - description: "~8 CPU, ~30G RAM" - profile_options: *profile_options - kubespawner_override: - mem_limit: 30G - mem_guarantee: 25G - node_selector: - node.kubernetes.io/instance-type: m5.2xlarge - - display_name: "Huge: m5.8xlarge" - description: "~16 CPU, ~60G RAM" - profile_options: *profile_options - kubespawner_override: - mem_limit: 60G - mem_guarantee: 50G + mem_limit: 8G + mem_guarantee: 6.5G node_selector: - node.kubernetes.io/instance-type: m5.8xlarge - + node.kubernetes.io/instance-type: m5.large + # Using 'latest' for now so updates do not require 2i2c + # involvement. + image: quay.io/henrykmodzelewski/2i2c-eosc350:latest scheduling: userScheduler: enabled: true diff --git a/config/clusters/utoronto/common.values.yaml b/config/clusters/utoronto/common.values.yaml index 984e89b54c..b9bb4b9d84 100644 --- a/config/clusters/utoronto/common.values.yaml +++ b/config/clusters/utoronto/common.values.yaml @@ -27,7 +27,7 @@ jupyterhub: interface_selector: true org: name: University of Toronto - logo_url: https://raw.githubusercontent.com/utoronto-2i2c/homepage/master/extra-assets/images/home-hero.png + logo_url: https://raw.githubusercontent.com/2i2c-org/default-hub-homepage/utoronto-prod/extra-assets/images/home-hero.png url: https://www.utoronto.ca/ designed_by: name: 2i2c diff --git a/config/clusters/utoronto/r-common.values.yaml b/config/clusters/utoronto/r-common.values.yaml index bd9b0441f9..c9e534251b 100644 --- a/config/clusters/utoronto/r-common.values.yaml +++ b/config/clusters/utoronto/r-common.values.yaml @@ -17,4 +17,4 @@ jupyterhub: defaultUrl: /rstudio image: name: quay.io/2i2c/utoronto-r-image - tag: "c5ec9db8ccb2" + tag: "56882376ee4b" diff --git a/config/clusters/utoronto/r-staging.values.yaml b/config/clusters/utoronto/r-staging.values.yaml index 52a155ad2e..97c3b40832 100644 --- a/config/clusters/utoronto/r-staging.values.yaml +++ b/config/clusters/utoronto/r-staging.values.yaml @@ -5,6 +5,10 @@ jupyterhub: - hosts: [r-staging.datatools.utoronto.ca] secretName: https-auto-tls hub: + db: + pvc: + # prod stores logs, so let's make it big + storage: 10Gi config: CILogonOAuthenticator: oauth_callback_url: https://r-staging.datatools.utoronto.ca/hub/oauth_callback diff --git a/config/clusters/victor/common.values.yaml b/config/clusters/victor/common.values.yaml index f57aa1a673..47136ec38c 100644 --- a/config/clusters/victor/common.values.yaml +++ b/config/clusters/victor/common.values.yaml @@ -17,11 +17,12 @@ basehub: add_staff_user_ids_to_admin_users: true add_staff_user_ids_of_type: "github" homepage: + gitRepoBranch: "victor" templateVars: org: - name: Victor - logo_url: https://lh3.googleusercontent.com/drive-viewer/AFDK6gOSmgurudnSJrUNMaIdOIEeu8aXUzWS9qZ0Oi3XO3_fFYdfjksmrPQrjv542v_81TCkVPlRT_Acf5BAojMEeYlEzF8nmw=w2880-h1368 - url: https://people.climate.columbia.edu/projects/view/2387 + name: VICTOR + logo_url: https://i.imgur.com/D2vXQ5k.png + url: https://victor.ldeo.columbia.edu designed_by: name: 2i2c url: https://2i2c.org diff --git a/deployer/cluster.py b/deployer/cluster.py index 73804c1f01..6b5149fda5 100644 --- a/deployer/cluster.py +++ b/deployer/cluster.py @@ -222,26 +222,16 @@ def auth_gcp(self): # Else, it'll just have a `zone` key set. Let's respect either. location = config.get("zone", config.get("region")) cluster = config["cluster"] - with tempfile.NamedTemporaryFile() as kubeconfig: - # CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE is removed as the action of - # "gcloud auth activate-server-account" will be secondary to it - # otherwise, and this env var can be set by GitHub Actions we use - # before using this deployer script to deploy hubs to clusters. - orig_cloudsdk_auth_credential_file_override = os.environ.pop( - "CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE", None - ) - orig_kubeconfig = os.environ.get("KUBECONFIG") - try: + + orig_file = os.environ.get("CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE") + orig_kubeconfig = os.environ.get("KUBECONFIG") + try: + with ( + tempfile.NamedTemporaryFile() as kubeconfig, + get_decrypted_file(key_path) as decrypted_file, + ): os.environ["KUBECONFIG"] = kubeconfig.name - with get_decrypted_file(key_path) as decrypted_key_path: - subprocess.check_call( - [ - "gcloud", - "auth", - "activate-service-account", - f"--key-file={os.path.abspath(decrypted_key_path)}", - ] - ) + os.environ["CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE"] = decrypted_file subprocess.check_call( [ @@ -257,10 +247,13 @@ def auth_gcp(self): ) yield - finally: - if orig_kubeconfig is not None: - os.environ["KUBECONFIG"] = orig_kubeconfig - if orig_cloudsdk_auth_credential_file_override is not None: - os.environ[ - "CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE" - ] = orig_cloudsdk_auth_credential_file_override + finally: + # restore modified environment variables to its previous state + if orig_kubeconfig is not None: + os.environ["KUBECONFIG"] = orig_kubeconfig + else: + os.environ.pop("KUBECONFIG") + if orig_file is not None: + os.environ["CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE"] = orig_file + else: + os.environ.pop("CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE") diff --git a/deployer/config_validation.py b/deployer/config_validation.py index 8684ede3c7..9165c03579 100644 --- a/deployer/config_validation.py +++ b/deployer/config_validation.py @@ -162,7 +162,15 @@ def validate_authenticator_config(cluster_name, hub_name): For each hub of a specific cluster: - It asserts that when the JupyterHub GitHubOAuthenticator is used, then `Authenticator.allowed_users` is not set. - An error is raised otherwise. + + Before oauthenticator 16 / z2jh 3.0.0-beta.3+, allowed_users was an + additional requirement besides being part of an allowed github + organization or team, which made the config likely to not be what we + intended. + + FIXME: Remove this after we have upgraded to oauthenticator 16 / z2jh + 3.0.0-beta.3+, as that makes this config reasonable again, where a + user can be allowed independently from allowing an organization. """ _prepare_helm_charts_dependencies_and_schemas() diff --git a/deployer/generate/common.py b/deployer/generate/common.py new file mode 100644 index 0000000000..53adf4323e --- /dev/null +++ b/deployer/generate/common.py @@ -0,0 +1,91 @@ +import os +import secrets +import string +import subprocess +from pathlib import Path + +import jinja2 + +from ..utils import print_colour + +REPO_ROOT = Path(__file__).parent.parent.parent + + +def generate_cluster_config_file(cluster_config_directory, provider, vars): + """ + Generates the `config//cluster.yaml` config + """ + with open(REPO_ROOT / f"config/clusters/templates/{provider}/cluster.yaml") as f: + cluster_yaml_template = jinja2.Template(f.read()) + with open(cluster_config_directory / "cluster.yaml", "w") as f: + f.write(cluster_yaml_template.render(**vars)) + + +def generate_support_files(cluster_config_directory, vars): + """ + Generates files related to support components. + + They are required to deploy the support chart for the cluster + and to configure the Prometheus instance. + + Generates: + - `config//support.values.yaml` + - `config//enc-support.secret.values.yaml` + """ + # Generate the suppport values file `support.values.yaml` + print_colour("Generating the support values file...", "yellow") + with open(REPO_ROOT / "config/clusters/templates/common/support.values.yaml") as f: + support_values_yaml_template = jinja2.Template(f.read()) + + with open(cluster_config_directory / "support.values.yaml", "w") as f: + f.write(support_values_yaml_template.render(**vars)) + print_colour(f"{cluster_config_directory}/support.values.yaml created") + + # Generate and encrypt prometheus credentials into `enc-support.secret.values.yaml` + print_colour("Generating the prometheus credentials encrypted file...", "yellow") + alphabet = string.ascii_letters + string.digits + credentials = { + "username": "".join(secrets.choice(alphabet) for i in range(64)), + "password": "".join(secrets.choice(alphabet) for i in range(64)), + } + with open( + REPO_ROOT / "config/clusters/templates/common/support.secret.values.yaml" + ) as f: + support_secret_values_yaml_template = jinja2.Template(f.read()) + with open(cluster_config_directory / "enc-support.secret.values.yaml", "w") as f: + f.write(support_secret_values_yaml_template.render(**credentials)) + + # Encrypt the private key + subprocess.check_call( + [ + "sops", + "--in-place", + "--encrypt", + cluster_config_directory / "enc-support.secret.values.yaml", + ] + ) + print_colour( + f"{cluster_config_directory}/enc-support.values.yaml created and encrypted" + ) + + +def generate_config_directory(vars): + """ + Generates the required `config` directory for hubs on a cluster if it doesn't exit + and returns its name. + """ + cluster_config_directory = REPO_ROOT / "config/clusters" / vars["cluster_name"] + + print_colour( + f"Checking if cluster config directory {cluster_config_directory} exists...", + "yellow", + ) + if os.path.exists(cluster_config_directory): + print_colour(f"{cluster_config_directory} already exists.") + return cluster_config_directory + + # Create the cluster config directory and initial `cluster.yaml` file + os.makedirs(cluster_config_directory) + print_colour(f"{cluster_config_directory} created") + + return cluster_config_directory diff --git a/deployer/generate/generate_aws_cluster.py b/deployer/generate/generate_aws_cluster.py index 14e8f81652..65c428c483 100644 --- a/deployer/generate/generate_aws_cluster.py +++ b/deployer/generate/generate_aws_cluster.py @@ -1,24 +1,24 @@ +""" +Generate required files for an AWS cluster + +Generates: +- an eksctl jsonnet file +- a .tfvars file +- An ssh-key (the private part is encrypted) +""" import os import subprocess -from pathlib import Path import jinja2 import typer from ..cli_app import app +from ..utils import print_colour +from .common import REPO_ROOT, generate_config_directory, generate_support_files -REPO_ROOT = Path(__file__).parent.parent.parent - - -def aws(cluster_name, hub_type, cluster_region): - """ - Generate required files for an AWS cluster - Generates: - - an eksctl jsonnet file - - a .tfvars file - - An ssh-key (the private part is encrypted) - """ +def generate_infra_files(vars): + cluster_name = vars["cluster_name"] with open(REPO_ROOT / "eksctl/template.jsonnet") as f: # jsonnet files have `}}` in there, which causes jinja2 to # freak out. So we use different delimiters. @@ -31,22 +31,20 @@ def aws(cluster_name, hub_type, cluster_region): variable_end_string=">>", ) + print_colour("Generating the eksctl jsonnet file...", "yellow") + jsonnet_file_path = REPO_ROOT / "eksctl" / f"{cluster_name}.jsonnet" + with open(jsonnet_file_path, "w") as f: + f.write(jsonnet_template.render(**vars)) + print_colour(f"{jsonnet_file_path} created") + + print_colour("Generating the terraform infrastructure file...", "yellow") with open(REPO_ROOT / "terraform/aws/projects/template.tfvars") as f: tfvars_template = jinja2.Template(f.read()) - vars = { - "cluster_name": cluster_name, - "hub_type": hub_type, - "cluster_region": cluster_region, - } - - with open(REPO_ROOT / "eksctl" / f"{cluster_name}.jsonnet", "w") as f: - f.write(jsonnet_template.render(**vars)) - - with open( - REPO_ROOT / "terraform/aws/projects" / f"{cluster_name}.tfvars", "w" - ) as f: + tfvars_file_path = REPO_ROOT / "terraform/aws/projects" / f"{cluster_name}.tfvars" + with open(tfvars_file_path, "w") as f: f.write(tfvars_template.render(**vars)) + print_colour(f"{tfvars_file_path} created") subprocess.check_call( [ @@ -89,4 +87,19 @@ def generate_aws_cluster( """ Automatically generate the files required to setup a new cluster on AWS """ - aws(cluster_name, hub_type, cluster_region) + + # These are the variables needed by the templates used to generate the cluster config file + # and support files + vars = { + "cluster_name": cluster_name, + "hub_type": hub_type, + "cluster_region": cluster_region, + } + + generate_infra_files(vars) + + # Automatically generate the config directory + cluster_config_directory = generate_config_directory(vars) + + # Generate the support files + generate_support_files(cluster_config_directory, vars) diff --git a/deployer/generate/generate_gcp_cluster.py b/deployer/generate/generate_gcp_cluster.py index 208ce501b4..4f5820848a 100644 --- a/deployer/generate/generate_gcp_cluster.py +++ b/deployer/generate/generate_gcp_cluster.py @@ -1,111 +1,73 @@ -import os -import secrets -import string -import subprocess -from pathlib import Path +""" +Generates the ` terraform file required to create a GCP cluster +and the required `config` directory for hubs on a GCP cluster. +Generates the following files: +- terraform/gcp/projects/.tfvars` +- `config//cluster.yaml` +- `config//support.values.yaml` +- `config//enc-support.secret.values.yaml` + +""" import jinja2 import typer +from typing_extensions import Annotated from ..cli_app import app from ..utils import print_colour - -REPO_ROOT = Path(__file__).parent.parent.parent +from .common import ( + REPO_ROOT, + generate_cluster_config_file, + generate_config_directory, + generate_support_files, +) -def generate_terraform_file(cluster_name, cluster_region, project_id, hub_type): +def generate_terraform_file(vars): """ Generates the `terraform/gcp/projects/.tfvars` terraform file required to create a GCP cluster """ - with open(REPO_ROOT / f"terraform/gcp/projects/{hub_type}-template.tfvars") as f: - tfvars_template = jinja2.Template(f.read()) - - vars = { - "cluster_name": cluster_name, - "cluster_region": cluster_region, - "project_id": project_id, - } - - print_colour("Generating the terraform infrastructure file...", "yellow") - with open( - REPO_ROOT / "terraform/gcp/projects" / f"{cluster_name}.tfvars", "w" - ) as f: - f.write(tfvars_template.render(**vars)) - print_colour(f"{REPO_ROOT}/terraform/gcp/projects/{cluster_name}.tfvars created") - - -def generate_cluster_config_file(cluster_config_directory, vars): - """ - Generates the `config//cluster.yaml` config - """ - with open(REPO_ROOT / "config/clusters/templates/gcp/cluster.yaml") as f: - cluster_yaml_template = jinja2.Template(f.read()) - with open(cluster_config_directory / "cluster.yaml", "w") as f: - f.write(cluster_yaml_template.render(**vars)) - - -def generate_support_files(cluster_config_directory, vars): - """ - Generates files related to support components. - - They are required to deploy the support chart for the cluster - and to configure the Prometheus instance. - - Generates: - - `config//support.values.yaml` - - `config//enc-support.secret.values.yaml` - """ - # Generate the suppport values file `support.values.yaml` - print_colour("Generating the support values file...", "yellow") - with open(REPO_ROOT / "config/clusters/templates/gcp/support.values.yaml") as f: - support_values_yaml_template = jinja2.Template(f.read()) - - with open(cluster_config_directory / "support.values.yaml", "w") as f: - f.write(support_values_yaml_template.render(**vars)) - print_colour(f"{cluster_config_directory}/support.values.yaml created") - - # Generate and encrypt prometheus credentials into `enc-support.secret.values.yaml` - print_colour("Generating the prometheus credentials encrypted file...", "yellow") - alphabet = string.ascii_letters + string.digits + string.punctuation - credentials = { - "username": "".join(secrets.choice(alphabet) for i in range(64)), - "password": "".join(secrets.choice(alphabet) for i in range(64)), - } with open( - REPO_ROOT / "config/clusters/templates/gcp/support.secret.values.yaml" + REPO_ROOT / f'terraform/gcp/projects/{vars["hub_type"]}-template.tfvars' ) as f: - support_secret_values_yaml_template = jinja2.Template(f.read()) - with open(cluster_config_directory / "enc-support.secret.values.yaml", "w") as f: - f.write(support_secret_values_yaml_template.render(**credentials)) + tfvars_template = jinja2.Template(f.read()) - # Encrypt the private key - subprocess.check_call( - [ - "sops", - "--in-place", - "--encrypt", - cluster_config_directory / "enc-support.secret.values.yaml", - ] - ) - print_colour( - f"{cluster_config_directory}/enc-support.values.yaml created and encrypted" + print_colour("Generating the terraform infrastructure file...", "yellow") + tfvars_file_path = ( + REPO_ROOT / "terraform/gcp/projects" / f'{vars["cluster_name"]}.tfvars' ) + with open(tfvars_file_path, "w") as f: + f.write(tfvars_template.render(**vars)) + print_colour(f"{tfvars_file_path} created") -def generate_config_directory( - cluster_name, cluster_region, project_id, hub_type, hub_name +@app.command() +def generate_gcp_cluster( + cluster_name: Annotated[ + str, typer.Option(prompt="Please type the name of the new cluster") + ], + project_id: Annotated[ + str, typer.Option(prompt="Please insert the Project ID of the GCP project") + ], + hub_name: Annotated[ + str, + typer.Option( + prompt="Please insert the name of first hub to add to the cluster" + ), + ], + cluster_region: Annotated[ + str, typer.Option(prompt="Please insert the name of the cluster region") + ] = "us-central1", + hub_type: Annotated[ + str, typer.Option(prompt="Please insert the hub type of the first hub") + ] = "basehub", ): """ - Generates the required `config` directory for hubs on a GCP cluster - - Generates the following files: - - `config//cluster.yaml` - - `config//support.values.yaml` - - `config//enc-support.secret.values.yaml` + Automatically generates the initial files, required to setup a new cluster on GCP """ - cluster_config_directory = REPO_ROOT / "config/clusters" / cluster_name - + # These are the variables needed by the templates used to generate the cluster config file + # and support files vars = { "cluster_name": cluster_name, "hub_type": hub_type, @@ -114,40 +76,14 @@ def generate_config_directory( "hub_name": hub_name, } - print_colour( - "Checking if cluster config directory {cluster_config_directory} exists...", - "yellow", - ) - if os.path.exists(cluster_config_directory): - print_colour(f"{cluster_config_directory} already exists.") - return + # Automatically generate the terraform config file + generate_terraform_file(vars) + + # Automatically generate the config directory + cluster_config_directory = generate_config_directory(vars) # Create the cluster config directory and initial `cluster.yaml` file - os.makedirs(cluster_config_directory) - print_colour(f"{cluster_config_directory} created") - generate_cluster_config_file(cluster_config_directory, vars) + generate_cluster_config_file(cluster_config_directory, "gcp", vars) # Generate the support files generate_support_files(cluster_config_directory, vars) - - -@app.command() -def generate_gcp_cluster( - cluster_name: str = typer.Option(..., prompt="Name of the cluster"), - cluster_region: str = typer.Option(..., prompt="Cluster region"), - project_id: str = typer.Option(..., prompt="Project ID of the GCP project"), - hub_type: str = typer.Option( - ..., prompt="Type of hub. Choose from `basehub` or `daskhub`" - ), - hub_name: str = typer.Option(..., prompt="Name of the first hub"), -): - """ - Automatically generates the initial files, required to setup a new cluster on GCP - """ - # Automatically generate the terraform config file - generate_terraform_file(cluster_name, cluster_region, project_id, hub_type) - - # Automatically generate the config directory - generate_config_directory( - cluster_name, cluster_region, project_id, hub_type, hub_name - ) diff --git a/docs/howto/features/allow-unlisted-profile-choice.md b/docs/howto/features/allow-unlisted-profile-choice.md index 86a233b38a..85b48d60a9 100644 --- a/docs/howto/features/allow-unlisted-profile-choice.md +++ b/docs/howto/features/allow-unlisted-profile-choice.md @@ -20,7 +20,7 @@ jupyterhub: enabled: True display_name: "Custom image" validation_regex: "^.+:.+$" - validation_message: "Must be an image location, matching ^.+:.+$" + validation_message: "Must be a publicly available docker image, of form :" kubespawner_override: image: "{value}" choices: @@ -56,7 +56,7 @@ In the `profileList` for the hub in question, add a profile like this: enabled: True display_name: "Custom image" validation_regex: "^.+:.+$" - validation_message: "Must be an image location, matching ^.+:.+$" + validation_message: "Must be a publicly available docker image, of form :" kubespawner_override: image: "{value}" choices: {} diff --git a/eksctl/smithsonian.jsonnet b/eksctl/smithsonian.jsonnet index 943ba20bbc..de44946890 100644 --- a/eksctl/smithsonian.jsonnet +++ b/eksctl/smithsonian.jsonnet @@ -28,6 +28,12 @@ local notebookNodes = [ { instanceType: "r5.xlarge" }, { instanceType: "r5.4xlarge" }, { instanceType: "r5.16xlarge" }, + { + instanceType: "g4dn.xlarge", + tags+: { + "k8s.io/cluster-autoscaler/node-template/resources/nvidia.com/gpu": "1" + }, + }, ]; local daskNodes = [ // Node definitions for dask worker nodes. Config here is merged diff --git a/helm-charts/basehub/templates/home-dirsize-reporter.yaml b/helm-charts/basehub/templates/home-dirsize-reporter.yaml index 494ac3c05e..d002634ddc 100644 --- a/helm-charts/basehub/templates/home-dirsize-reporter.yaml +++ b/helm-charts/basehub/templates/home-dirsize-reporter.yaml @@ -37,16 +37,16 @@ spec: # From https://github.com/yuvipanda/prometheus-dirsize-exporter image: quay.io/yuvipanda/prometheus-dirsize-exporter:v2.0 resources: - # Provide *very few* resources for this collector, as it can + # Provide limited resources for this collector, as it can # baloon up (especially in CPU) quite easily. We are quite ok with # the collection taking a while as long as we aren't costing too much # CPU or RAM requests: - memory: 16Mi + memory: 128Mi cpu: 0.01 limits: cpu: 0.05 - memory: 128Mi + memory: 256Mi command: - dirsize-exporter - /shared-volume diff --git a/helm-charts/basehub/values.yaml b/helm-charts/basehub/values.yaml index 4019a160e2..c58cea667f 100644 --- a/helm-charts/basehub/values.yaml +++ b/helm-charts/basehub/values.yaml @@ -698,22 +698,27 @@ jupyterhub: ) c.Spawner.pre_spawn_hook = ensure_db_pvc 05-gh-teams: | + # Re-assignes c.KubeSpawner.profile_list to a callable that filters the + # initial configuration of profile_list based on the user's github + # org/team membership as declared via "allowed_teams" read from + # profile_list profiles. + # + # This is only done if: + # - GitHubOAuthenticator is used + # - GitHubOAuthenticator.populate_teams_in_auth_state is True + # import copy from textwrap import dedent - from tornado import gen, web + from tornado import web from oauthenticator.github import GitHubOAuthenticator - # Make a copy of the original profile_list, as that is the data we will work with original_profile_list = c.KubeSpawner.profile_list - # This has to be a gen.coroutine, not async def! Kubespawner uses gen.maybe_future to - # run this, and that only seems to recognize tornado coroutines, not async functions! - # We can convert this to async def once that has been fixed upstream. - @gen.coroutine - def custom_profile_list(spawner): + async def profile_list_allowed_teams_filter(spawner): """ - Dynamically set allowed list of user profiles based on GitHub teams user is part of. + Returns the initially configured profile_list filtered based on if + the spawning user is part the profiles' specified GitHub org/teams. Adds a 'allowed_teams' key to profile_list, with a list of GitHub teams (of the form org-name:team-name) for which the profile is made available. @@ -728,17 +733,17 @@ jupyterhub: # If populate_teams_in_auth_state is not set, github teams are not fetched # So we just don't do any of this filtering, and let anyone into everything if spawner.authenticator.populate_teams_in_auth_state == False: - return original_profile_list + return original_profile_list - auth_state = yield spawner.user.get_auth_state() + auth_state = await spawner.user.get_auth_state() if not auth_state or "teams" not in auth_state: - if spawner.user.name == 'deployment-service-check': - # For our hub deployer health checker, ignore all this logic - print("Ignoring allowed_teams check for deployment-service-check") - return original_profile_list - print(f"User {spawner.user.name} does not have any auth_state set") - raise web.HTTPError(403) + if spawner.user.name == 'deployment-service-check': + # For our hub deployer health checker, ignore all this logic + print("Ignoring allowed_teams check for deployment-service-check") + return original_profile_list + print(f"User {spawner.user.name} does not have any auth_state set") + raise web.HTTPError(403) # Make a list of team names of form org-name:team-name # This is the same syntax used by allowed_organizations traitlet of GitHubOAuthenticator @@ -752,41 +757,41 @@ jupyterhub: # otherwise we might end up modifying it by mistake profile_list_copy = copy.deepcopy(original_profile_list) for profile in profile_list_copy: - # If there is no ':' in allowed_teams, it's an org and we should check that - # differently - allowed_orgs = set([o for o in profile.get('allowed_teams', []) if ':' not in o]) - allowed_teams = set([t for t in profile.get('allowed_teams', []) if ':' in t]) - - # Keep the profile is the user is part of *any* team listed in allowed_teams - # If allowed_teams is empty or not set, it'll not be accessible to *anyone* - if allowed_teams & teams: - allowed_profiles.append(profile) - print(f"Allowing profile {profile['display_name']} for user {spawner.user.name} based on team membership") - elif allowed_orgs: - for org in allowed_orgs: - user_in_org = yield spawner.authenticator._check_membership_allowed_organizations( - org, spawner.user.name, auth_state['access_token'] - ) - if user_in_org: + # If there is no ':' in allowed_teams, it's an org and we should check that + # differently + allowed_orgs = set([o for o in profile.get('allowed_teams', []) if ':' not in o]) + allowed_teams = set([t for t in profile.get('allowed_teams', []) if ':' in t]) + + # Keep the profile is the user is part of *any* team listed in allowed_teams + # If allowed_teams is empty or not set, it'll not be accessible to *anyone* + if allowed_teams & teams: allowed_profiles.append(profile) - print(f"Allowing profile {profile['display_name']} for user {spawner.user.name} based on org membership") - break - else: - print(f"Dropping profile {profile['display_name']} for user {spawner.user.name}") + print(f"Allowing profile {profile['display_name']} for user {spawner.user.name} based on team membership") + elif allowed_orgs: + for org in allowed_orgs: + user_in_org = await spawner.authenticator._check_membership_allowed_organizations( + org, spawner.user.name, auth_state['access_token'] + ) + if user_in_org: + allowed_profiles.append(profile) + print(f"Allowing profile {profile['display_name']} for user {spawner.user.name} based on org membership") + break + else: + print(f"Dropping profile {profile['display_name']} for user {spawner.user.name}") if len(allowed_profiles) == 0: - # If no profiles are allowed, user should not be able to spawn anything! - # If we don't explicitly stop this, user will be logged into the 'default' settings - # set in singleuser, without any profile overrides. Not desired behavior - # FIXME: User doesn't actually see this error message, just the generic 403. - error_msg = dedent(f""" - Your GitHub team membership is insufficient to launch any server profiles. + # If no profiles are allowed, user should not be able to spawn anything! + # If we don't explicitly stop this, user will be logged into the 'default' settings + # set in singleuser, without any profile overrides. Not desired behavior + # FIXME: User doesn't actually see this error message, just the generic 403. + error_msg = dedent(f""" + Your GitHub team membership is insufficient to launch any server profiles. - GitHub teams you are a member of that this JupyterHub knows about are {', '.join(teams)}. + GitHub teams you are a member of that this JupyterHub knows about are {', '.join(teams)}. - If you are part of additional teams, log out of this JupyterHub and log back in to refresh that information. - """) - raise web.HTTPError(403, error_msg) + If you are part of additional teams, log out of this JupyterHub and log back in to refresh that information. + """) + raise web.HTTPError(403, error_msg) return allowed_profiles @@ -796,7 +801,7 @@ jupyterhub: if c.KubeSpawner.profile_list: # Customize list of profiles dynamically, rather than override options form. # This is more secure, as users can't override the options available to them via the hub API - c.KubeSpawner.profile_list = custom_profile_list + c.KubeSpawner.profile_list = profile_list_allowed_teams_filter 06-salted-username: | # Allow anonymizing username to not store *any* PII diff --git a/helm-charts/images/hub/dynamic-image-building-requirements.txt b/helm-charts/images/hub/dynamic-image-building-requirements.txt index 225a86b394..bad7b75cee 100644 --- a/helm-charts/images/hub/dynamic-image-building-requirements.txt +++ b/helm-charts/images/hub/dynamic-image-building-requirements.txt @@ -3,4 +3,4 @@ git+https://github.com/yuvipanda/jupyterhub-configurator@ed7e3a0df1e3d625d10903e # Brings on using `unlisted_choice` in profile options per https://github.com/2i2c-org/infrastructure/issues/2146 git+https://github.com/jupyterhub/kubespawner@5a90351adba7d65286bd5e00e82f156011bf7b83 # Brings in https://github.com/yuvipanda/prototype-kubespawner-dynamic-building-ui -git+https://github.com/yuvipanda/prototype-kubespawner-dynamic-building-ui.git@b36ece00b5e7fcba5d4485e7ab70992705601c3c +git+https://github.com/yuvipanda/prototype-kubespawner-dynamic-building-ui.git@2f9b899cb6d7ea91f0e5f69c48562a1cd73fc3da diff --git a/helm-charts/images/hub/unlisted-choice-requirements.txt b/helm-charts/images/hub/unlisted-choice-requirements.txt index 27ee25150b..e02283cf4e 100644 --- a/helm-charts/images/hub/unlisted-choice-requirements.txt +++ b/helm-charts/images/hub/unlisted-choice-requirements.txt @@ -1,3 +1,3 @@ git+https://github.com/yuvipanda/jupyterhub-configurator@ed7e3a0df1e3d625d10903ef7d7fd9c2fbb548db # Brings on using `unlisted_choice` in profile options per https://github.com/2i2c-org/infrastructure/issues/2146 -git+https://github.com/jupyterhub/kubespawner@934ef321f72e58bd680d35ea5fd6780b2b8b52c7 +git+https://github.com/jupyterhub/kubespawner@8cc569c78bcdb342e694f7344219e43d522f4809 diff --git a/helm-charts/support/Chart.yaml b/helm-charts/support/Chart.yaml index d0125c57a1..705ecef8ad 100644 --- a/helm-charts/support/Chart.yaml +++ b/helm-charts/support/Chart.yaml @@ -15,13 +15,13 @@ dependencies: - name: prometheus # NOTE: CHECK INSTRUCTIONS UNDER prometheus.server.command IN support/values.yaml # EACH TIME THIS VERSION IS BUMPED! - version: 23.1.0 + version: 24.1.0 repository: https://prometheus-community.github.io/helm-charts # Grafana for dashboarding of metrics. # https://github.com/grafana/helm-charts/tree/main/charts/grafana - name: grafana - version: 6.58.6 + version: 6.59.0 repository: https://grafana.github.io/helm-charts # ingress-nginx for a k8s Ingress resource controller that routes traffic from @@ -35,7 +35,7 @@ dependencies: # cluster-autoscaler for k8s clusters where it doesn't come out of the box (EKS) # https://github.com/kubernetes/autoscaler/tree/master/charts/cluster-autoscaler - name: cluster-autoscaler - version: 9.29.1 + version: 9.29.3 repository: https://kubernetes.github.io/autoscaler condition: cluster-autoscaler.enabled diff --git a/helm-charts/support/templates/pd-ssd.yaml b/helm-charts/support/templates/pd-ssd.yaml deleted file mode 100644 index d174b8b167..0000000000 --- a/helm-charts/support/templates/pd-ssd.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Create an SSD StorageClass for use by Prometheus -# See https://kubernetes.io/docs/concepts/storage/storage-classes/#gce for details -kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: ssd -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-ssd \ No newline at end of file diff --git a/helm-charts/support/templates/storageclass/gke.yaml b/helm-charts/support/templates/storageclass/gke.yaml new file mode 100644 index 0000000000..6422ca257f --- /dev/null +++ b/helm-charts/support/templates/storageclass/gke.yaml @@ -0,0 +1,15 @@ +# https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver#create_a_storageclass +# has more information about setting up StorageClass for GCP PD CSI Driver, +# for use in GKE environments. +{{- if .Values.prometheusStorageClass.gke.enabled }} +allowVolumeExpansion: true +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: {{ .Values.prometheusStorageClass.gke.name }} +parameters: {{ .Values.prometheusStorageClass.gke.parameters | toJson }} +provisioner: pd.csi.storage.gke.io +# Don't delete the backing disk when the PVC is deleted +reclaimPolicy: Retain +volumeBindingMode: WaitForFirstConsumer +{{- end }} diff --git a/helm-charts/support/values.schema.yaml b/helm-charts/support/values.schema.yaml index cd0836efcb..d63c7bced4 100644 --- a/helm-charts/support/values.schema.yaml +++ b/helm-charts/support/values.schema.yaml @@ -143,6 +143,49 @@ properties: type: string description: | Password for basic auth protecting prometheus + + prometheusStorageClass: + type: object + additionalProperties: false + description: | + Provision a separate storageClass specifically for storing prometheus + data. Lets us control retentionPolicy (so we do not lose the data + when the cluster is deleted) and type of disk used (for performance + tuning) + required: + - gke + properties: + gke: + type: object + additionalProperties: false + description: | + Provision storageClass in a GKE environment, with the appropriate + GCP PD CSI provisioner. + + https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver has + more information about this provisioner. + required: + - enabled + - parameters + - name + properties: + enabled: + type: boolean + description: | + Enable creating this StorageClass + parameters: + type: object + additionalProperties: true + description: | + Parameters defining properties of the volume provisioned by this + StorageClass. + + For the GCP CSI driver in use here, the parameters are documented at + https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver + name: + type: string + description: | + Name of the StorageClass to create global: type: object additionalProperties: true diff --git a/helm-charts/support/values.yaml b/helm-charts/support/values.yaml index b4beb7da08..686deaeec0 100644 --- a/helm-charts/support/values.yaml +++ b/helm-charts/support/values.yaml @@ -180,21 +180,10 @@ prometheus: --storage.tsdb.path=/data \ --web.console.libraries=/etc/prometheus/console_libraries \ --web.console.templates=/etc/prometheus/consoles \ - --web.enable-lifecycle \ - --storage.tsdb.min-block-duration=5m \ - --storage.tsdb.max-block-duration=5m" + --web.enable-lifecycle" # extraFlags MUST BE UPDATED in prometheus.server.defaultFlagsOverride as well extraFlags: - web.enable-lifecycle - # We seem to loose data when restarting prometheus during upgrades, and we - # also have had memory peaking issues during startup. These flags may help - # us reduce the data loss to at most 30m and has been observed to reduce - # the memory peaking before prometheus 2.45 at least. - # - # ref: https://github.com/prometheus/prometheus/issues/6934#issuecomment-1099293120 - # - - storage.tsdb.min-block-duration=5m - - storage.tsdb.max-block-duration=5m # retention MUST BE UPDATED in prometheus.server.defaultFlagsOverride as well retention: 366d # Keep data for at least 1 year @@ -277,7 +266,7 @@ prometheus: # hub.jupyter.org/network-access-hub: "true" persistentVolume: - size: 200Gi + size: 400Gi service: type: ClusterIP @@ -455,6 +444,19 @@ nvidiaDevicePlugin: enabled: false version: "stable" +# Setup a separate storageClass specifically for prometheus data +prometheusStorageClass: + gke: + # Defaults to false, until all GKE clusters have been manually + # migrated. Could default to true after that. + enabled: false + # pd-balanced is SSD backed, much faster than spinning standard disks and + # cheaper than pd-ssd. We add the -retain to indicate the retainPolicy + # of Retain, rather than the default of Delete + name: balanced-rwo-retain + parameters: + type: pd-balanced + # A placeholder as global values that can be referenced from the same location # of any chart should be possible to provide, but aren't necessarily provided or # used. diff --git a/terraform/gcp/cluster.tf b/terraform/gcp/cluster.tf index 5fd1a8e689..8cc052c338 100644 --- a/terraform/gcp/cluster.tf +++ b/terraform/gcp/cluster.tf @@ -185,7 +185,6 @@ resource "google_container_node_pool" "core" { location = google_container_cluster.cluster.location version = var.k8s_versions.core_nodes_version - initial_node_count = 1 autoscaling { min_node_count = 1 @@ -213,6 +212,12 @@ resource "google_container_node_pool" "core" { node_config { + # Balanced disks are much faster than standard disks, and much cheaper + # than SSD disks. It contributes heavily to how fast new nodes spin up, + # as images being pulled takes up a lot of new node spin up time. + # Faster disks provide faster image pulls! + disk_type = "pd-balanced" + labels = { "hub.jupyter.org/node-purpose" = "core", "k8s.dask.org/node-purpose" = "core" diff --git a/terraform/gcp/main.tf b/terraform/gcp/main.tf index 32d37409bf..5c25c9af1d 100644 --- a/terraform/gcp/main.tf +++ b/terraform/gcp/main.tf @@ -18,6 +18,12 @@ terraform { source = "hashicorp/kubernetes" version = "~> 2.18" } + # Used to decrypt sops encrypted secrets containing PagerDuty keys + sops = { + # ref: https://registry.terraform.io/providers/carlpett/sops/latest + source = "carlpett/sops" + version = "~> 0.7.2" + } } } diff --git a/terraform/gcp/pagerduty.tf b/terraform/gcp/pagerduty.tf new file mode 100644 index 0000000000..7b79f3c012 --- /dev/null +++ b/terraform/gcp/pagerduty.tf @@ -0,0 +1,60 @@ +/** +* This file defines alerts and notification channels for sending information to +* PagerDuty in order to trigger incidents. This relies on pre-registered +* PagerDuty services with "stackdriver" integrations in 2i2c's PagerDuty +* account. +* +* - PagerDuty services in 2i2c's PagerDuty account: +* https://2i2c-org.pagerduty.com/service-directory/?direction=asc&query=&team_ids=all +* - GCP docs about managing notification channels: +* https://cloud.google.com/monitoring/support/notification-options +* +*/ +data "sops_file" "pagerduty_service_integration_keys" { + # Read sops encrypted file containing integration key for pagerduty + source_file = "secret/enc-pagerduty-service-integration-keys.secret.yaml" +} + +resource "google_monitoring_notification_channel" "pagerduty_disk_space" { + project = var.project_id + display_name = "PagerDuty Disk Space Alerts" + type = "pagerduty" + sensitive_labels { + service_key = data.sops_file.pagerduty_service_integration_keys.data["disk_space"] + } +} + +resource "google_monitoring_alert_policy" "disk_space_full_alert" { + + display_name = "Available disk space < ${var.filestore_alert_available_percent}% on ${var.project_id}" + combiner = "OR" + + conditions { + display_name = "Simple Health Check Endpoint" + condition_threshold { + # Alert based on free bytes left on the filesystem + filter = <<-EOT + resource.type = "filestore_instance" + AND metric.type = "file.googleapis.com/nfs/server/free_bytes_percent" + EOT + duration = "300s" + + # Trigger if free space is < 10% + threshold_value = var.filestore_alert_available_percent + comparison = "COMPARISON_LT" + + aggregations { + # https://cloud.google.com/monitoring/alerts/concepts-indepth#duration has + # more info on alignment + alignment_period = "300s" + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_NONE" + } + } + } + + project = var.project_id + + # Send a notification to our PagerDuty channel when this is triggered + notification_channels = [google_monitoring_notification_channel.pagerduty_disk_space.name] +} diff --git a/terraform/gcp/projects/2i2c-uk.tfvars b/terraform/gcp/projects/2i2c-uk.tfvars index df9336af68..39d3464599 100644 --- a/terraform/gcp/projects/2i2c-uk.tfvars +++ b/terraform/gcp/projects/2i2c-uk.tfvars @@ -1,10 +1,17 @@ prefix = "two-eye-two-see-uk" project_id = "two-eye-two-see-uk" -zone = "europe-west2-b" -region = "europe-west2" +zone = "europe-west2-b" +region = "europe-west2" +regional_cluster = true -core_node_machine_type = "n1-highmem-4" +k8s_versions = { + min_master_version : "1.27.4-gke.900", + core_nodes_version : "1.27.4-gke.900", + notebook_nodes_version : "1.27.4-gke.900", +} + +core_node_machine_type = "n2-highmem-4" enable_network_policy = true # Setup a filestore for in-cluster NFS @@ -15,7 +22,7 @@ notebook_nodes = { "user" : { min : 0, max : 20, - machine_type : "n1-highmem-4" + machine_type : "n2-highmem-4" }, } diff --git a/terraform/gcp/projects/awi-ciroh.tfvars b/terraform/gcp/projects/awi-ciroh.tfvars index 65920f8b50..00423fd574 100644 --- a/terraform/gcp/projects/awi-ciroh.tfvars +++ b/terraform/gcp/projects/awi-ciroh.tfvars @@ -5,7 +5,7 @@ region = "us-central1" core_node_machine_type = "n2-highmem-4" enable_network_policy = true enable_filestore = true -filestore_capacity_gb = 1024 +filestore_capacity_gb = 1536 k8s_versions = { min_master_version : "1.25.8-gke.500", diff --git a/terraform/gcp/projects/callysto.tfvars b/terraform/gcp/projects/callysto.tfvars index fb45e5c3fb..431d4a6450 100644 --- a/terraform/gcp/projects/callysto.tfvars +++ b/terraform/gcp/projects/callysto.tfvars @@ -1,13 +1,14 @@ prefix = "callysto" project_id = "callysto-202316" -zone = "northamerica-northeast1-b" -region = "northamerica-northeast1" +zone = "northamerica-northeast1-b" +region = "northamerica-northeast1" +regional_cluster = true k8s_versions = { - min_master_version : "1.25.6-gke.1000", - core_nodes_version : "1.25.6-gke.1000", - notebook_nodes_version : "1.25.6-gke.1000", + min_master_version : "1.27.4-gke.900", + core_nodes_version : "1.27.4-gke.900", + notebook_nodes_version : "1.27.4-gke.900", } core_node_machine_type = "n2-highmem-2" diff --git a/terraform/gcp/projects/cloudbank.tfvars b/terraform/gcp/projects/cloudbank.tfvars index 883976e3eb..4acfafc83f 100644 --- a/terraform/gcp/projects/cloudbank.tfvars +++ b/terraform/gcp/projects/cloudbank.tfvars @@ -1,19 +1,26 @@ prefix = "cb" project_id = "cb-1003-1696" -zone = "us-central1-b" -region = "us-central1" +zone = "us-central1-b" +region = "us-central1" +regional_cluster = false + +k8s_versions = { + min_master_version : "1.26.5-gke.2100", + core_nodes_version : "1.26.5-gke.2100", + notebook_nodes_version : "1.26.4-gke.1400", +} +# FIXME: We have a temporary core node pool setup with n2-highmem-4 and +# pd-balanced. This node pool still has standard though, but has been +# cordoned. +# core_node_machine_type = "n1-highmem-4" +enable_network_policy = true enable_filestore = true filestore_capacity_gb = 1024 -# Multi-tenant cluster, network policy is required to enforce separation between hubs -enable_network_policy = true - -regional_cluster = false - notebook_nodes = { "user" : { min : 0, diff --git a/terraform/gcp/projects/daskhub-template.tfvars b/terraform/gcp/projects/daskhub-template.tfvars index 4c756e7e65..26b5c0b3c4 100644 --- a/terraform/gcp/projects/daskhub-template.tfvars +++ b/terraform/gcp/projects/daskhub-template.tfvars @@ -25,26 +25,18 @@ enable_filestore = true filestore_capacity_gb = 1024 user_buckets = { - "scratch-staging" : { - "delete_after" : 7 - }, - "scratch" : { + "scratch-{{ hub_name }}" : { "delete_after" : 7 }, # Tip: add more scratch buckets below, if this cluster will be multi-tenant } hub_cloud_permissions = { - "staging" : { + "{{ hub_name }}" : { requestor_pays : true, - bucket_admin_access : ["scratch-staging", "persistent-staging"], - hub_namespace : "staging" + bucket_admin_access : ["scratch-{{ hub_name }}"], + hub_namespace : "{{ hub_name }}" }, - "prod" : { - requestor_pays : true, - bucket_admin_access : ["scratch", "persistent"], - hub_namespace : "prod" - } # Tip: add more namespaces below, if this cluster will be multi-tenant } diff --git a/terraform/gcp/projects/hhmi.tfvars b/terraform/gcp/projects/hhmi.tfvars new file mode 100644 index 0000000000..3466c94128 --- /dev/null +++ b/terraform/gcp/projects/hhmi.tfvars @@ -0,0 +1,53 @@ +prefix = "hhmi" +project_id = "hhmi" + +zone = "us-west2" +region = "us-west2" + +# Default to a HA cluster for reliability +regional_cluster = true + +core_node_machine_type = "n2-highmem-4" + +# Network policy is required to enforce separation between hubs on multi-tenant clusters +# Tip: uncomment the line below if this cluster will be multi-tenant +# enable_network_policy = true + +# Setup a filestore for in-cluster NFS +enable_filestore = true +filestore_capacity_gb = 1024 + +user_buckets = {} +hub_cloud_permissions = {} + +# Setup notebook node pools +notebook_nodes = { + "small" : { + min : 0, + max : 100, + machine_type : "n2-highmem-4", + }, + "medium" : { + min : 0, + max : 100, + machine_type : "n2-highmem-16", + }, + "large" : { + min : 0, + max : 100, + machine_type : "n2-highmem-64", + }, +} + +# Setup a single node pool for dask workers. +# +# A not yet fully established policy is being developed about using a single +# node pool, see https://github.com/2i2c-org/infrastructure/issues/2687. +# +dask_nodes = { + "worker" : { + min : 0, + max : 200, + machine_type : "n2-highmem-16", + }, +} \ No newline at end of file diff --git a/terraform/gcp/projects/linked-earth.tfvars b/terraform/gcp/projects/linked-earth.tfvars index 170f7c00fd..ee3fb5ecca 100644 --- a/terraform/gcp/projects/linked-earth.tfvars +++ b/terraform/gcp/projects/linked-earth.tfvars @@ -1,11 +1,20 @@ -prefix = "linked-earth" -project_id = "linked-earth-hubs" -zone = "us-central1-c" -region = "us-central1" -core_node_machine_type = "e2-highmem-4" +prefix = "linked-earth" +project_id = "linked-earth-hubs" + +zone = "us-central1-c" +region = "us-central1" +regional_cluster = true + +k8s_versions = { + min_master_version : "1.27.4-gke.900", + core_nodes_version : "1.27.4-gke.900", + notebook_nodes_version : "1.27.4-gke.900", + dask_nodes_version : "1.27.4-gke.900", +} + +core_node_machine_type = "n2-highmem-4" enable_network_policy = true -# Setup a filestore for in-cluster NFS enable_filestore = true filestore_capacity_gb = 1024 @@ -23,12 +32,12 @@ notebook_nodes = { "small" : { min : 0, max : 100, - machine_type : "e2-highmem-4" + machine_type : "n2-highmem-4" }, "medium" : { min : 0, max : 100, - machine_type : "e2-highmem-16" + machine_type : "n2-highmem-16" }, } diff --git a/terraform/gcp/projects/m2lines.tfvars b/terraform/gcp/projects/m2lines.tfvars index 501db17700..902d5baeb6 100644 --- a/terraform/gcp/projects/m2lines.tfvars +++ b/terraform/gcp/projects/m2lines.tfvars @@ -1,14 +1,22 @@ -prefix = "m2lines" -project_id = "m2lines-hub" -core_node_machine_type = "n1-highmem-4" - -enable_network_policy = true +prefix = "m2lines" +project_id = "m2lines-hub" # GPUs not available in us-central1-b zone = "us-central1-c" region = "us-central1" regional_cluster = true +k8s_versions = { + min_master_version : "1.27.4-gke.900", + core_nodes_version : "1.27.4-gke.900", + notebook_nodes_version : "1.27.4-gke.900", + dask_nodes_version : "1.27.4-gke.900", +} + +core_node_machine_type = "n2-highmem-4" +enable_network_policy = true + + # Setup a filestore for in-cluster NFS enable_filestore = true filestore_capacity_gb = 2048 diff --git a/terraform/gcp/projects/meom-ige.tfvars b/terraform/gcp/projects/meom-ige.tfvars index 442e8c85c3..144d4e461f 100644 --- a/terraform/gcp/projects/meom-ige.tfvars +++ b/terraform/gcp/projects/meom-ige.tfvars @@ -1,15 +1,18 @@ prefix = "meom-ige" project_id = "meom-ige-cnrs" -zone = "us-central1-b" -region = "us-central1" +zone = "us-central1-b" +region = "us-central1" +regional_cluster = false -core_node_machine_type = "n1-highmem-2" +k8s_versions = { + min_master_version : "1.27.4-gke.900", + core_nodes_version : "1.27.4-gke.900", + notebook_nodes_version : "1.27.4-gke.900", +} -# Single-tenant cluster, network policy not needed -enable_network_policy = false - -regional_cluster = false +core_node_machine_type = "n2-highmem-4" +enable_network_policy = false notebook_nodes = { "small" : { @@ -37,7 +40,6 @@ notebook_nodes = { max : 20, machine_type : "n1-standard-64" }, - } # Setup a single node pool for dask workers. diff --git a/terraform/gcp/projects/pilot-hubs.tfvars b/terraform/gcp/projects/pilot-hubs.tfvars index 2d6b328947..865a53c247 100644 --- a/terraform/gcp/projects/pilot-hubs.tfvars +++ b/terraform/gcp/projects/pilot-hubs.tfvars @@ -1,18 +1,22 @@ prefix = "pilot-hubs" project_id = "two-eye-two-see" -zone = "us-central1-b" -region = "us-central1" - -core_node_machine_type = "n1-highmem-4" +zone = "us-central1-b" +region = "us-central1" +regional_cluster = false -# Multi-tenant cluster, network policy is required to enforce separation between hubs -enable_network_policy = true +k8s_versions = { + min_master_version : "1.26.5-gke.2100", + core_nodes_version : "1.26.5-gke.2100", + notebook_nodes_version : "1.26.4-gke.1400", + dask_nodes_version : "1.26.5-gke.1400", +} -regional_cluster = false +core_node_machine_type = "n2-highmem-4" +enable_network_policy = true enable_filestore = true -filestore_capacity_gb = 4096 +filestore_capacity_gb = 5120 notebook_nodes = { "user" : { diff --git a/terraform/gcp/projects/qcl.tfvars b/terraform/gcp/projects/qcl.tfvars index 5ce11208c4..4d5473fb75 100644 --- a/terraform/gcp/projects/qcl.tfvars +++ b/terraform/gcp/projects/qcl.tfvars @@ -1,13 +1,19 @@ prefix = "qcl" project_id = "qcl-hub" -zone = "europe-west1-d" -region = "europe-west1" +zone = "europe-west1-d" +region = "europe-west1" +regional_cluster = true + +k8s_versions = { + min_master_version : "1.25.10-gke.2700", + core_nodes_version : "1.24.9-gke.3200", + notebook_nodes_version : "1.24.9-gke.3200", +} core_node_machine_type = "n2-highmem-2" enable_network_policy = true -# Setup a filestore for in-cluster NFS enable_filestore = true filestore_capacity_gb = 2048 diff --git a/terraform/gcp/secret/enc-pagerduty-service-integration-keys.secret.yaml b/terraform/gcp/secret/enc-pagerduty-service-integration-keys.secret.yaml new file mode 100644 index 0000000000..2d00bdef4c --- /dev/null +++ b/terraform/gcp/secret/enc-pagerduty-service-integration-keys.secret.yaml @@ -0,0 +1,19 @@ +#ENC[AES256_GCM,data:FxCCu/DMShf4HlOeIL07yuTb5n8Df2viI9NMXk/oxab9Rs4Kn51gVIU3PlIIXM4M3mYVYKVRvpF3j+SmtqXj4lLPpBPK0tn9j7cLw1Z/3J7a,iv:cIotHiLKrulCAs/Yq5DCJhvv69M1ahIz3RXmV1kmgwk=,tag:AZzq1JcRkpm4mbRYSHTONA==,type:comment] +#ENC[AES256_GCM,data:trbapbX57yDKIOw5W2ezVZasO9FVQqHzphqbaDhsyDLvOClBTGdkn4Yeitubv6hqmoNxMkauU/a6y98Gr3rn00gupNlX+t+o1afRmMIEwL5o,iv:9VunnZES/oPFkJDsoFBPup6Eeh8ClmwDXVZMeTahT88=,tag:KfarI7CY8FrQyH+sZ6+ivw==,type:comment] +#ENC[AES256_GCM,data:aEcAW7H5s6bbkKEIGsn3oPmterD1uRjY6s/i6n616A32prTfu7DHoCSSJlOl/SFBBaNdUFy69gRb0qnsEVLxe3Jbx5XWGGvRBNQLwd/GDjTG,iv:W40bcs3XwEEMZsPmO0w+xYqfydbq/1VGm+art6foqcU=,tag:tbrP4q3Iwb1B28zxbz9Z9A==,type:comment] +#ENC[AES256_GCM,data:dnFbCqSAHLriCyq3EAJia0GketuNdLhLWRX0qKxGmDsyTF00BJLv8nKGnUcML+nUecsoFb3dvWlsUUOvRZ3BznJgYrfF9SGq6dMCU7+q79DhBLdU6A==,iv:AbZIdZcl2kD3yWpzV23xfZ7dIWK1wqY0WiUYsB1e0Z4=,tag:wavRZFwVWX6yf+30IgtWLw==,type:comment] +disk_space: ENC[AES256_GCM,data:nwR0G3PGhlSnnne5pisymfvlAN+yPRkTWTG71/jaJb0=,iv:2WQdn69bFBB0XbBeIm7juuh/w1PckvFmYfEGEmq6Hps=,tag:ovZmaZ4a7Ady5x4moNClPA==,type:str] +sops: + kms: [] + gcp_kms: + - resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs + created_at: "2023-09-06T21:56:23Z" + enc: CiUA4OM7eO/6AvFQhsiSCXcba7zOnYZC45WPgkTzOsO+ivGKt1lIEkkAq2nhVWRy1UZ3GuuIlNwadpU5nz4UTLN4lKOWjQVa+qu0E7fzmPyTKXAM0nNXDxKr+ji1/AsvhsTi/DwCdb98NPU8uFOmH5AL + azure_kv: [] + hc_vault: [] + age: [] + lastmodified: "2023-09-06T21:56:24Z" + mac: ENC[AES256_GCM,data:J1oep9rSOE20uHN1+YP/Mg04s/NG3svnY0AYiLZOY9dXHKWjcSGd+EcBIsD9UvkApGhftyWSBhdA38zjASMzq7pyUepf8/kGNL/OQiLsfQEST9/2OrCTRtRdUS8ryyxw6cUv1E0cCFpKFC8hZuf28J86zNCie2jwyCep1IVEghw=,iv:QWSDNl6vw6b0MoMdcTaXFqZL0jghodYy/z5ouLt2r3k=,tag:NEwRIpyvYJEFy9UQEr4uNQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/terraform/gcp/variables.tf b/terraform/gcp/variables.tf index 45cb956fea..76613e1483 100644 --- a/terraform/gcp/variables.tf +++ b/terraform/gcp/variables.tf @@ -309,6 +309,15 @@ variable "filestore_tier" { EOT } +variable "filestore_alert_available_percent" { + type = number + default = 10 + description = <<-EOT + % of free space in filestore available under which to fire an alert to pagerduty. + EOT +} + + variable "enable_node_autoprovisioning" { type = bool default = false