diff --git a/.github/workflows/pull-request-test.yml b/.github/workflows/pull-request-test.yml index d626f5c72d..af76359d39 100644 --- a/.github/workflows/pull-request-test.yml +++ b/.github/workflows/pull-request-test.yml @@ -147,6 +147,7 @@ jobs: useSession, checkWorkflows, rstudioSession, + dashboardV2, ] steps: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8441811a8f..c9580b622b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,65 @@ +0.59.0 +------ + + + +0.58.0 +------ + +Renku ``0.58.0`` fixes several issues related to Renku 2.0 search, and also squashes a bug where the +Renku 2.0 dashboard displayed content not related to you. + + +User-Facing Changes +~~~~~~~~~~~~~~~~~~~ + +**✨ Improvements** + +- **UI**: Polish Renku 2.0 pages and elements according to the latest design changes (`#3254 `__). + +**🐞 Bug Fixes** + +- **Search Services**: Resolve issues that caused items to be missing from Renku 2.0 search, including the search for members when adding members to projects and groups. +- **UI**: Resolve an issue where the Renku 2.0 dashboard displayed projects and groups that the user was not a member of (`#3289 `__) +- **UI**: Fix a bug where clicking on 'Show all my projects' on the Renku 2.0 dashboard redirected to a page displaying not only the user's projects but also others' projects (`#3289 `__) +- **UI**: Prevent glitches in the new session details sections (`#3313 `__). + +Internal Changes +~~~~~~~~~~~~~~~~ + +**Improvements** + +- **UI**: Update Storybook to show Renku 2.0 re-usable elements (`#3254 `__). +- **UI**: Add and edit connected services from the admin panel (`#3329 `__). +- **Search Services**: Allow to re-provision the index from data-services and as part of a SOLR schema migration +- **Helm chart**: Add RBAC for K8s cache for new AmaltheaSessions custom resource +- **Gateway**: Add extra credentials for the data service for the new AmaltheaSessions +- **Gateway**: Remove unused Python code +- **Data services**: Support event queue re-provisioning +- **Data services**: Support listing projects and groups by direct membership + +**🐞 Bug Fixes** + +- **Data services**: Do not use gather() in when listing projects +- **Data services**: Order resource classes by GPU, CPU, RAM and storage +- **Data services**: Following redirects when sending requests to git repositories +- **Data services**: Allow unsetting secrets for cloud storage +- **Helm chart**: Increase the connection timeout for the Authzed database health checks + +Individual Components +~~~~~~~~~~~~~~~~~~~~~ + +- `renku-search 0.6.1 `_ +- `renku-ui 3.36.0 `_ +- `renku-ui 3.37.0 `_ +- `renku-ui 3.37.1 `_ +- `renku-gateway 1.1.0 `_ +- `renku-data-services 0.21.0 `__ +- `renku-data-services 0.22.0 `__ + 0.57.2 ------ @@ -15,7 +74,7 @@ User-facing Changes **Bug Fixes** -- **UI**: show the correct repository access status +- **UI**: show the correct repository access status - **Sessions**: allow paused sessions with cloud storage secrets to resume normally Internal Changes @@ -70,7 +129,7 @@ Individual Components Renku `0.57.0` brings a suite of new features and improvements to the Renku 2.0 beta. As a main highlight, you can now save and reuse the credentials for data sources. No more copy/paste on every session launch! We have also made small improvements to sharing, search, and sessions in Renku 2.0. -For a full list of changes, see the list below. +For a full list of changes, see the list below. NOTE to administrators: Upgrading the `csi-rclone` component will unmount all cloud storage for all diff --git a/cypress-tests/cypress/e2e/dashboardV2.cy.ts b/cypress-tests/cypress/e2e/dashboardV2.cy.ts new file mode 100644 index 0000000000..1bb9d6d7b9 --- /dev/null +++ b/cypress-tests/cypress/e2e/dashboardV2.cy.ts @@ -0,0 +1,80 @@ +import { getRandomString, validateLogin } from "../support/commands/general"; +import { generatorProjectName } from "../support/commands/projects"; +import { + createProjectIfMissingAPIV2, + deleteProjectFromAPIV2, getProjectByNamespaceAPIV2, + getUserNamespaceAPIV2, ProjectIdentifierV2 +} from "../support/utils/projectsV2.utils"; +const projectTestConfig = { + projectAlreadyExists: false, + projectName: generatorProjectName("dashboardV2"), +}; + +const prefixProjectTitle = "My Renku Project"; +const sessionId = ["dashboardV2", getRandomString()]; + +describe("Dashboard v2 - Authenticated user", () => { + const projectIdentifier: ProjectIdentifierV2 = { + slug: projectTestConfig.projectName, + id: null, + namespace: null, + }; + + after(() => { + if (!projectTestConfig.projectAlreadyExists && projectIdentifier.id != null){ + deleteProjectFromAPIV2(projectIdentifier); + getProjectByNamespaceAPIV2(projectIdentifier).then((response) => { + expect(response.status).to.equal(404); + }); + } + + }); + + beforeEach(() => { + // Restore the session + cy.session( + sessionId, + () => { + cy.robustLogin(); + }, + validateLogin + ); + getUserNamespaceAPIV2().then((namespace) => { + if (namespace) { + projectIdentifier.namespace = namespace; + createProjectIfMissingAPIV2({ + visibility: "private", + name: `${prefixProjectTitle} ${projectIdentifier.slug}`, + namespace, + slug: projectIdentifier.slug, + }).then((project) => projectIdentifier.id=project.id) + } else { + cy.log('No user namespace found, project cannot be created.'); + } + }); + }); + + it("Can see own project on the dashboard", () => { + cy.visit("v2"); + cy.getDataCy("dashboard-project-list").find("a").should("have.length.at.least", 1); + cy.getDataCy("dashboard-project-list").find("a").should("contain.text", `${prefixProjectTitle} ${projectIdentifier.slug}`); + cy.getDataCy("dashboard-project-list").find("a").should("contain.text", projectIdentifier.slug); + }); + + it("Can find project in the search results", () => { + cy.visit("v2"); + cy.getDataCy("view-my-projects-btn").click(); + cy.getDataCy("search-card").should("have.length.at.least", 1); + cy.getDataCy("search-card").should("contain.text", `${prefixProjectTitle} ${projectIdentifier.slug}`); + }); +}); + +describe("Dashboard v2 - Non-Authenticated user", () => { + it("Cannot see projects and groups on Dashboard when logged out", () => { + cy.visit("v2"); + cy.getDataCy("projects-container").contains("No 2.0 projects."); + cy.getDataCy("view-other-projects-btn").should("be.visible"); + cy.getDataCy("groups-container").contains("No 2.0 groups."); + cy.getDataCy("view-other-groups-btn").should("be.visible"); + }); +}); diff --git a/cypress-tests/cypress/support/commands/login.ts b/cypress-tests/cypress/support/commands/login.ts index 6623084aad..087d123d55 100644 --- a/cypress-tests/cypress/support/commands/login.ts +++ b/cypress-tests/cypress/support/commands/login.ts @@ -21,7 +21,7 @@ const register = ( firstName?: string, lastName?: string ) => { - cy.visit("/login"); + cy.visit("/api/auth/login"); // ? wait to be assess whether tokens were refreshed automatically or we really need to register cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting @@ -141,7 +141,7 @@ function logout() { cy.get("#profile-dropdown").should("be.visible").click(); cy.get("#logout-link").should("be.visible").click(); // Make sure we fully log out - cy.wait(1_000); + cy.wait(15_000); } export default function registerLoginCommands() { diff --git a/cypress-tests/cypress/support/utils/projectsV2.utils.ts b/cypress-tests/cypress/support/utils/projectsV2.utils.ts new file mode 100644 index 0000000000..1770aaff91 --- /dev/null +++ b/cypress-tests/cypress/support/utils/projectsV2.utils.ts @@ -0,0 +1,55 @@ +export type ProjectIdentifierV2 = { + slug: string; + namespace?: string; + id?: string; +}; + +export interface NewProjectV2Props extends ProjectIdentifierV2 { + visibility?: "public" | "private"; + name: string; +} + +/** Get the namespace of the logged in user from the API. */ +export function getUserNamespaceAPIV2(): Cypress.Chainable { + return cy.request({ failOnStatusCode: false, method: "GET", url: `api/data/namespaces?minimum_role=owner` }) + .then((response) => { + if (response.status === 200) { + const userNamespace = response.body?.filter((namespace) => namespace.namespace_kind === "user"); + return userNamespace && userNamespace.length > 0 ? userNamespace[0].slug : null; + } + return null; + }); +} + +/** Get a project by using only the API. */ +export function getProjectByNamespaceAPIV2(newProjectProps: ProjectIdentifierV2): Cypress.Chainable { + return cy.request({ failOnStatusCode: false, method: "GET", url: `api/data/projects/${newProjectProps.namespace}/${newProjectProps.slug}` }); +} + +/** Create a project (if the project is missing) by using only the API. */ +export function createProjectIfMissingAPIV2(newProjectProps: NewProjectV2Props) { + return getProjectByNamespaceAPIV2(newProjectProps) + .then((response) => { + if (response.status != 200) { + return cy.request({ + method: "POST", + url: "api/data/projects", + body: newProjectProps, + headers: { + 'Content-Type': 'application/json' + } + }); + } else { + return response.body; + } + }); +} + +/** Delete a project by using only the API. */ +export function deleteProjectFromAPIV2(projectIdentifier: ProjectIdentifierV2) { + return cy.request({ + failOnStatusCode: false, + method: "DELETE", + url: `api/data/projects/${projectIdentifier.id}`, + }); +} diff --git a/docs/how-to-guides/admin/configurations/external-gitlab.rst b/docs/how-to-guides/admin/configurations/external-gitlab.rst index 5088afd9a7..903178ca5f 100644 --- a/docs/how-to-guides/admin/configurations/external-gitlab.rst +++ b/docs/how-to-guides/admin/configurations/external-gitlab.rst @@ -19,7 +19,7 @@ Callback URLs: .. code-block:: console - https:///login/redirect/gitlab + https:///api/auth/callback https:///api/auth/gitlab/token Scopes: diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 3c962635ef..0b4a298299 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -313,6 +313,7 @@ unmounting unpause unpushed unschedulable +unsetting untracked untracked updatable diff --git a/helm-chart/renku/templates/_helpers.tpl b/helm-chart/renku/templates/_helpers.tpl index 7cec86a39f..c7d07db31d 100644 --- a/helm-chart/renku/templates/_helpers.tpl +++ b/helm-chart/renku/templates/_helpers.tpl @@ -176,3 +176,38 @@ renku-authz-tls-cert {{- define "renku.CASecretName" -}} renku-ca {{- end -}} + +{{- define "renku.events.streamEnvVars" -}} +- name: "RS_REDIS_QUEUE_PROJECT_CREATED" + value: "project.created" +- name: "RS_REDIS_QUEUE_PROJECT_UPDATED" + value: "project.updated" +- name: "RS_REDIS_QUEUE_PROJECT_REMOVED" + value: "project.removed" +- name: "RS_REDIS_QUEUE_PROJECTAUTH_ADDED" + value: "projectAuth.added" +- name: "RS_REDIS_QUEUE_PROJECTAUTH_UPDATED" + value: "projectAuth.updated" +- name: "RS_REDIS_QUEUE_PROJECTAUTH_REMOVED" + value: "projectAuth.removed" +- name: "RS_REDIS_QUEUE_USER_ADDED" + value: "user.added" +- name: "RS_REDIS_QUEUE_USER_UPDATED" + value: "user.updated" +- name: "RS_REDIS_QUEUE_USER_REMOVED" + value: "user.removed" +- name: "RS_REDIS_QUEUE_GROUP_ADDED" + value: "group.added" +- name: "RS_REDIS_QUEUE_GROUP_UPDATED" + value: "group.updated" +- name: "RS_REDIS_QUEUE_GROUP_REMOVED" + value: "group.removed" +- name: "RS_REDIS_QUEUE_GROUPMEMBER_ADDED" + value: "groupMember.added" +- name: "RS_REDIS_QUEUE_GROUPMEMBER_UPDATED" + value: "groupMember.updated" +- name: "RS_REDIS_QUEUE_GROUPMEMBER_REMOVED" + value: "groupMember.removed" +- name: "RS_REDIS_QUEUE_DATASERVICE_ALLEVENTS" + value: "data_service.all_events" +{{- end -}} \ No newline at end of file diff --git a/helm-chart/renku/templates/authz/deployment.yaml b/helm-chart/renku/templates/authz/deployment.yaml index 306f3ac814..d61dbc8239 100644 --- a/helm-chart/renku/templates/authz/deployment.yaml +++ b/helm-chart/renku/templates/authz/deployment.yaml @@ -108,6 +108,8 @@ spec: - -addr=127.0.0.1:50051 - -tls - -tls-server-name={{ template "renku.fullname" . }}-authz + - -connect-timeout + - "3s" timeoutSeconds: 3 periodSeconds: 10 readinessProbe: @@ -118,6 +120,8 @@ spec: - -addr=127.0.0.1:50051 - -tls - -tls-server-name={{ template "renku.fullname" . }}-authz + - -connect-timeout + - "3s" timeoutSeconds: 3 periodSeconds: 10 resources: diff --git a/helm-chart/renku/templates/data-service/rbac.yaml b/helm-chart/renku/templates/data-service/rbac.yaml index 6680e2fe2d..c242893a24 100644 --- a/helm-chart/renku/templates/data-service/rbac.yaml +++ b/helm-chart/renku/templates/data-service/rbac.yaml @@ -1,3 +1,4 @@ +{{- if .Values.dataService.rbac.create -}} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -85,3 +86,4 @@ subjects: - kind: ServiceAccount name: {{ template "renku.fullname" . }}-data-service namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/helm-chart/renku/templates/notebooks/role.yaml b/helm-chart/renku/templates/notebooks/role.yaml index 13ca5ad43d..1ebe6b008e 100644 --- a/helm-chart/renku/templates/notebooks/role.yaml +++ b/helm-chart/renku/templates/notebooks/role.yaml @@ -67,5 +67,17 @@ rules: - list - get - watch + - apiGroups: + - amalthea.dev + resources: + - amaltheasessions + verbs: + - create + - update + - delete + - patch + - list + - get + - watch {{ end }} {{ end }} diff --git a/helm-chart/renku/templates/search/search-provision-deployment.yaml b/helm-chart/renku/templates/search/search-provision-deployment.yaml index 537818f36f..bd77e719e3 100644 --- a/helm-chart/renku/templates/search/search-provision-deployment.yaml +++ b/helm-chart/renku/templates/search/search-provision-deployment.yaml @@ -48,10 +48,7 @@ spec: key: {{ .Values.global.redis.existingSecretPasswordKey }} - name: RS_REDIS_MASTER_SET value: {{ .Values.global.redis.sentinel.masterSet | quote }} - {{- range $k, $v := .Values.global.events.streams }} - - name: RS_REDIS_QUEUE_{{ $k }} - value: {{ $v }} - {{- end }} + {{- include "renku.events.streamEnvVars" . | nindent 12 }} - name: RS_SOLR_URL value: "http://{{ template "solr.fullname" . }}:{{ .Values.global.solr.port }}" - name: RS_SOLR_CORE diff --git a/helm-chart/renku/values.yaml b/helm-chart/renku/values.yaml index ad6acfe9c0..159f3e2b48 100644 --- a/helm-chart/renku/values.yaml +++ b/helm-chart/renku/values.yaml @@ -85,25 +85,6 @@ global: ## for a new project based on its own version. ## NOTE should only be set for CI deployments and development purposes. cli_version: - ## Events related values definitions - events: - streams: - projectCreated: "project.created" - projectUpdated: "project.updated" - projectRemoved: "project.removed" - projectAuthAdded: "projectAuth.added" - projectAuthUpdated: "projectAuth.updated" - projectAuthRemoved: "projectAuth.removed" - userAdded: "user.added" - userUpdated: "user.updated" - userRemoved: "user.removed" - groupAdded: "group.added" - groupUpdated: "group.updated" - groupRemoved: "group.removed" - groupMemberAdded: "groupMember.added" - groupMemberUpdated: "groupMember.updated" - groupMemberRemoved: "groupMember.removed" - dataServiceAllEvents: "data_service.all_events" ## Note that the graph will not turned on by default until renku 0.4.0 graph: dbEventLog: @@ -678,7 +659,7 @@ ui: replicaCount: 1 image: repository: renku/renku-ui - tag: "3.35.1" + tag: "3.37.1" pullPolicy: IfNotPresent ## Optionally specify an array of imagePullSecrets. ## Secrets must be manually created in the namespace. @@ -867,7 +848,7 @@ ui: keepCookies: [] image: repository: renku/renku-ui-server - tag: "3.35.1" + tag: "3.37.1" pullPolicy: IfNotPresent imagePullSecrets: [] nameOverride: "" @@ -1125,15 +1106,15 @@ notebooks: gitRpcServer: image: name: renku/git-rpc-server - tag: "1.25.3" + tag: "1.26.1" gitHttpsProxy: image: name: renku/git-https-proxy - tag: "1.25.3" + tag: "1.26.1" gitClone: image: name: renku/git-clone - tag: "1.25.3" + tag: "1.26.1" service: type: ClusterIP port: 80 @@ -1186,12 +1167,12 @@ notebooks: sessionTypes: ["registered"] image: repository: renku/renku-notebooks-tests - tag: "1.25.3" + tag: "1.26.1" pullPolicy: IfNotPresent k8sWatcher: image: repository: renku/k8s-watcher - tag: "1.25.3" + tag: "1.26.1" pullPolicy: IfNotPresent resources: {} replicaCount: 1 @@ -1203,12 +1184,12 @@ notebooks: secretsMount: image: repository: renku/secrets-mount - tag: "1.25.3" + tag: "1.26.1" ssh: enabled: false image: repository: renku/ssh-jump-host - tag: "1.25.3" + tag: "1.26.1" pullPolicy: IfNotPresent resources: {} replicaCount: 1 @@ -1295,7 +1276,7 @@ gateway: secretKey: image: repository: renku/renku-gateway - tag: "1.0.4" + tag: "1.1.0" pullPolicy: IfNotPresent service: type: ClusterIP @@ -1388,7 +1369,7 @@ search: replicas: 1 image: repository: renku/search-api - tag: "0.5.0" + tag: "0.6.1" pullPolicy: IfNotPresent service: type: ClusterIP @@ -1401,7 +1382,7 @@ search: replicas: 1 image: repository: renku/search-provision - tag: "0.5.0" + tag: "0.6.1" pullPolicy: IfNotPresent service: type: ClusterIP @@ -1598,16 +1579,18 @@ platformInit: repository: renku/platform-init tag: "latest" dataService: + rbac: + create: true image: repository: renku/renku-data-service - tag: "0.20.0" + tag: "0.22.0" pullPolicy: IfNotPresent backgroundJobs: events: resources: {} image: repository: renku/data-service-background-jobs - tag: "0.20.0" + tag: "0.22.0" pullPolicy: IfNotPresent total: resources: {} @@ -1660,7 +1643,7 @@ authz: secretsStorage: image: repository: renku/secrets-storage - tag: "0.20.0" + tag: "0.22.0" pullPolicy: IfNotPresent service: type: ClusterIP diff --git a/scripts/generate-values/README.rst b/scripts/generate-values/README.rst index 48e89c77ce..dc2f94b35f 100644 --- a/scripts/generate-values/README.rst +++ b/scripts/generate-values/README.rst @@ -32,7 +32,7 @@ Configure the callback URLs: .. code-block:: - https:///login/redirect/gitlab + https:///api/auth/callback https:///api/auth/gitlab/token And set the scopes: diff --git a/scripts/init-db/gitlab_db_init.py b/scripts/init-db/gitlab_db_init.py index 67594dbd43..82038def55 100644 --- a/scripts/init-db/gitlab_db_init.py +++ b/scripts/init-db/gitlab_db_init.py @@ -83,7 +83,7 @@ def main(): config.gitlab_oauth_client_id, config.gitlab_oauth_client_secret, [ - f"{config.renku_url}/login/redirect/gitlab", + f"{config.renku_url}/api/auth/callback" f"{config.renku_url}/api/auth/gitlab/token", ], gitlab_db_connection,