Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,17 @@ renku-users-apispec: ## Download the "users" API spec
sed -e 's/- default: "general"//g' pkg/renkuapi/users/api.spec.yaml > pkg/renkuapi/users/api.spec.new.yaml
mv pkg/renkuapi/users/api.spec.new.yaml pkg/renkuapi/users/api.spec.yaml

.PHONY: renku-session-apispec
renku-session-apispec: ## Download the "session" API spec
curl -L -o pkg/renkuapi/session/api.spec.yaml https://raw.githubusercontent.com/SwissDataScienceCenter/renku-data-services/refs/heads/main/components/renku_data_services/session/api.spec.yaml
# sed -e 's/- default: "general"//g' pkg/renkuapi/users/api.spec.yaml > pkg/renkuapi/users/api.spec.new.yaml
# mv pkg/renkuapi/users/api.spec.new.yaml pkg/renkuapi/users/api.spec.yaml

.PHONY: generate
generate: pkg/renkuapi/users/users_gen.go ## Run go generate
generate: pkg/renkuapi/users/users_gen.go pkg/renkuapi/session/session_gen.go ## Run go generate

pkg/renkuapi/users/users_gen.go: pkg/renkuapi/users/api.spec.yaml
go generate pkg/renkuapi/users/users.go

pkg/renkuapi/session/session_gen.go: pkg/renkuapi/session/api.spec.yaml
go generate pkg/renkuapi/session/session.go
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require (
k8s.io/api v0.34.1
k8s.io/apimachinery v0.34.1
k8s.io/client-go v0.34.1
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
)

require (
Expand Down Expand Up @@ -71,7 +72,6 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
Expand Down
7 changes: 3 additions & 4 deletions pkg/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/github"
ns "github.com/SwissDataScienceCenter/renku-dev-utils/pkg/namespace"
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/renkuapi"
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/renkuapi/users"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -56,19 +55,19 @@ func login(cmd *cobra.Command, args []string) {

fmt.Printf("Renku URL: %s\n", url)

auth, err := renkuapi.NewRenkuApiAuth(url)
rac, err := renkuapi.NewRenkuApiClient(url)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

err = auth.Login(ctx)
err = rac.Auth().Login(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

ruc, err := users.NewRenkuUsersClient(url, users.WithRequestEditors(users.RequestEditorFn(auth.RequestEditor())))
ruc, err := rac.Users()
if err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ func logout(cmd *cobra.Command, args []string) {

fmt.Printf("Renku URL: %s\n", url)

auth, err := renkuapi.NewRenkuApiAuth(url)
rac, err := renkuapi.NewRenkuApiClient(url)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

err = auth.Logout(ctx)
err = rac.Auth().Logout(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func init() {
rootCmd.AddCommand(makeMeAdminCmd)
rootCmd.AddCommand(namespaceCmd)
rootCmd.AddCommand(openDeploymentCmd)
rootCmd.AddCommand(updateGlobalImagesCmd)
rootCmd.AddCommand(versionCmd)
}

Expand Down
135 changes: 135 additions & 0 deletions pkg/cmd/updateglobalimages.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package cmd

import (
"context"
"fmt"
"os"

"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/github"
ns "github.com/SwissDataScienceCenter/renku-dev-utils/pkg/namespace"
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/renkuapi"
"github.com/spf13/cobra"
)

var updateGlobalImagesCmd = &cobra.Command{
Use: "update-global-images",
Short: "Updates the global images",
Run: updateGlobalImages,
}

func updateGlobalImages(cmd *cobra.Command, args []string) {
ctx := context.Background()

release, err := cmd.Flags().GetString("release")
if err != nil {
fmt.Println(err)
os.Exit(1)
}

if release == "" {
cli, err := github.NewGitHubCLI("")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
release, err = cli.GetLatestRenkuRelease(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}

fmt.Printf("Renku release: %s\n", release)

url, err := cmd.Flags().GetString("url")
if err != nil {
fmt.Println(err)
os.Exit(1)
}

if url == "" {
namespace, err := cmd.Flags().GetString("namespace")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if namespace == "" {
cli, err := github.NewGitHubCLI("")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
namespace, err = ns.FindCurrentNamespace(ctx, cli)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}

deploymentURL, err := ns.GetDeploymentURL(namespace)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
url = deploymentURL.String()
}

fmt.Printf("Renku URL: %s\n", url)

rac, err := renkuapi.NewRenkuApiClient(url)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

if !rac.IsLoggedIn(ctx) {
fmt.Println("Error: not logged in")
showCmd := "rdu login"
if url != "" {
showCmd = showCmd + fmt.Sprintf(" --url %s", url)
}
if namespace != "" {
showCmd = showCmd + fmt.Sprintf(" --namespace %s", namespace)
}
fmt.Printf("Please run \"%s\" before running this command\n", showCmd)
os.Exit(1)
}

if !rac.IsAdmin(ctx) {
fmt.Println("Error: not an admin")
fmt.Println("Please make sure you are a Renku admin before running this command")
fmt.Println("See: rdu make-me-admin --help")
os.Exit(1)
}

rsc, err := rac.Session()
if err != nil {
fmt.Println(err)
os.Exit(1)
}

envs, err := rsc.GetGlobalEnvironments(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
fmt.Println(err)
os.Exit(1)
}

err = rsc.UpdateGlobalImages(ctx, github.GetGlobalImages(), release, envs, dryRun)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}

func init() {
updateGlobalImagesCmd.Flags().String("url", "", "instance URL")
updateGlobalImagesCmd.Flags().StringP("namespace", "n", "", "k8s namespace")
updateGlobalImagesCmd.Flags().String("release", "", "renku release")
updateGlobalImagesCmd.Flags().Bool("dry-run", false, "dry run")
}
27 changes: 27 additions & 0 deletions pkg/github/release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package github

import (
"context"
"encoding/json"
)

const renkuRepository = "SwissDataScienceCenter/renku"

func (cli *GitHubCLI) GetLatestRenkuRelease(ctx context.Context) (string, error) {
out, err := cli.RunCmd(ctx, "release", "view", "--repo", renkuRepository, "--json", "tagName")
if err != nil {
return "", err
}

var res gitHubReleaseViewOutput
err = json.Unmarshal(out, &res)
if err != nil {
return "", err
}

return res.TagName, nil
}

type gitHubReleaseViewOutput struct {
TagName string `json:"tagName"`
}
21 changes: 21 additions & 0 deletions pkg/github/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import "fmt"
// Maps repositories to namespace templates
var repoToNamespaceTemplateMap map[string]string

// Contains the list of Renku global images
var globalImagesSlice []string

func DeriveK8sNamespace(repo string, pr int) (string, error) {
tpl, found := repoToNamespaceTemplateMap[repo]
if found {
Expand All @@ -13,8 +16,13 @@ func DeriveK8sNamespace(repo string, pr int) (string, error) {
return "", fmt.Errorf("could not derive namespace from repository: %s", repo)
}

func GetGlobalImages() []string {
return globalImagesSlice[:]
}

func init() {
initRepoToNamespaceTemplateMap()
initGlobalImagesSlice()
}

func initRepoToNamespaceTemplateMap() {
Expand All @@ -25,3 +33,16 @@ func initRepoToNamespaceTemplateMap() {
"SwissDataScienceCenter/renku-ui": "renku-ci-ui-%d",
}
}

func initGlobalImagesSlice() {
// TODO: can we derive this from GitHub API calls?
prefix := "ghcr.io/swissdatasciencecenter/renku"
packageVariants := []string{"basic", "datascience"}
frontendVariants := []string{"jupyterlab", "ttyd", "vscodium"}
globalImagesSlice = make([]string, 0, len(packageVariants)*len(frontendVariants))
for _, packageVariant := range packageVariants {
for _, frontendVariant := range frontendVariants {
globalImagesSlice = append(globalImagesSlice, fmt.Sprintf("%s/py-%s-%s", prefix, packageVariant, frontendVariant))
}
}
}
89 changes: 89 additions & 0 deletions pkg/renkuapi/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package renkuapi

import (
"context"
"net/http"
"net/url"

"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/renkuapi/session"
"github.com/SwissDataScienceCenter/renku-dev-utils/pkg/renkuapi/users"
)

type RenkuApiClient struct {
baseURL *url.URL

auth *RenkuApiAuth

rsc *session.RenkuSessionClient
ruc *users.RenkuUsersClient

httpClient *http.Client
}

func NewRenkuApiClient(baseURL string) (rac *RenkuApiClient, err error) {
parsedURL, err := url.Parse(baseURL)
if err != nil {
return nil, err
}
if parsedURL.EscapedPath() == "/" {
parsedURL.Path = ""
}
rac = &RenkuApiClient{
baseURL: parsedURL,
}
if rac.httpClient == nil {
rac.httpClient = http.DefaultClient
}

// initialize auth
auth, err := NewRenkuApiAuth(baseURL)
if err != nil {
return nil, err
}
rac.auth = auth

return rac, nil
}

func (rac *RenkuApiClient) Auth() *RenkuApiAuth {
return rac.auth
}

func (rac *RenkuApiClient) IsLoggedIn(ctx context.Context) bool {
token, _ := rac.auth.GetAccessToken(ctx)
return token != ""
}

func (rac *RenkuApiClient) IsAdmin(ctx context.Context) bool {
ruc, err := rac.Users()
if err != nil {
return false
}
userInfo, err := ruc.GetUser(ctx)
if err != nil {
return false
}
return userInfo.IsAdmin
}

func (rac *RenkuApiClient) Session() (rsc *session.RenkuSessionClient, err error) {
if rac.rsc == nil {
rsc, err = session.NewRenkuSessionClient(rac.baseURL.String(), session.WithRequestEditors(session.RequestEditorFn(rac.auth.RequestEditor())))
if err != nil {
return nil, err
}
rac.rsc = rsc
}
return rac.rsc, nil
}

func (rac *RenkuApiClient) Users() (ruc *users.RenkuUsersClient, err error) {
if rac.ruc == nil {
ruc, err = users.NewRenkuUsersClient(rac.baseURL.String(), users.WithRequestEditors(users.RequestEditorFn(rac.auth.RequestEditor())))
if err != nil {
return nil, err
}
rac.ruc = ruc
}
return rac.ruc, nil
}
Loading