From a2a503edd83363adfa622ae5ce6eee609cde3a26 Mon Sep 17 00:00:00 2001 From: ale8k Date: Wed, 12 Jun 2024 14:22:06 +0100 Subject: [PATCH 1/3] JIMM rock Tested via: 1. Build rock 2. Change compose img 3. Spin up compose 4. Change env for jimm svc to include vault from vault.env 5. dc rm jimm 6. dc up jimm (no-depps) 7. Curled debug status CI: Tested on fork. --- .github/workflows/server-oci-release.yaml | 10 +- Makefile | 14 +- local/authy/main.go | 179 ---------------------- rocks/jimm.yaml | 58 +++++++ 4 files changed, 75 insertions(+), 186 deletions(-) delete mode 100644 local/authy/main.go create mode 100644 rocks/jimm.yaml diff --git a/.github/workflows/server-oci-release.yaml b/.github/workflows/server-oci-release.yaml index 4c63ad394..ab4d24034 100644 --- a/.github/workflows/server-oci-release.yaml +++ b/.github/workflows/server-oci-release.yaml @@ -24,8 +24,14 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build local images - run: make jimm-image + - name: ln rockcraft.yaml + run: ln -s ./rocks/jimm.yaml ./rockcraft.yaml + + - name: Build ROCK + uses: canonical/craft-actions/rockcraft-pack@main + + - name: Load ROCK into local registry + run: make load-rock - name: Push to github package run: | diff --git a/Makefile b/Makefile index c81e42d4f..0a225c8c7 100644 --- a/Makefile +++ b/Makefile @@ -68,9 +68,6 @@ version/version.txt: FORCE echo $(GIT_VERSION) > version/version.txt; \ fi -jimmsrv: version/commit.txt version/version.txt - go build -tags release -v $(PROJECT)/cmd/jemd - jimm-image: docker build --target deploy-env \ --build-arg="GIT_COMMIT=$(GIT_COMMIT)" \ @@ -98,8 +95,15 @@ push-microk8s: jimm-image docker tag jimm:latest localhost:32000/jimm:latest docker push localhost:32000/jimm:latest -get-local-auth: - @go run ./local/authy +rock: + -rm *.rock + -ln -s ./rocks/jimm.yaml ./rockcraft.yaml + rockcraft pack + -rm ./rockcraft.yaml + +load-rock: + $(eval jimm_version := $(shell cat ./rocks/jimm.yaml | yq ".version")) + @sudo /snap/rockcraft/current/bin/skopeo --insecure-policy copy oci-archive:jimm_${jimm_version}_amd64.rock docker-daemon:jimm:latest define check_dep if ! which $(1) > /dev/null; then\ diff --git a/local/authy/main.go b/local/authy/main.go deleted file mode 100644 index 6aee0ca70..000000000 --- a/local/authy/main.go +++ /dev/null @@ -1,179 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net/http" - "net/http/cookiejar" - "net/url" - "strings" - - "github.com/canonical/jimm/internal/rpc" - "github.com/go-macaroon-bakery/macaroon-bakery/v3/httpbakery" - jujuparams "github.com/juju/juju/rpc/params" - "gopkg.in/errgo.v1" -) - -// A ResponseHandler is a function that is used by OpenWebBrowser to -// perform further processing with a response. A ResponseHandler should -// parse the response to determine the next action, close the body of the -// incoming response and perform queries in order to return the final -// response to the caller. The final response should not have its body -// closed. -type responseHandler func(*http.Client, *http.Response) (*http.Response, error) - -// OpenWebBrowser returns a function that simulates opening a web browser -// to complete a login. This function only returns a non-nil error to its -// caller if there is an error initialising the client. If rh is non-nil -// it will be called with the *http.Response that was received by the -// client. This handler should arrange for any required further -// processing and return the result. -func openWebBrowser(rh responseHandler) func(u *url.URL) error { - return func(u *url.URL) error { - jar, err := cookiejar.New(nil) - if err != nil { - return errgo.Mask(err) - } - client := &http.Client{ - Jar: jar, - } - resp, err := client.Get(u.String()) - if err != nil { - fmt.Printf("error getting login URL %s: %s\n", u.String(), err) - return nil - } - if rh != nil { - resp, err = rh(client, resp) - if err != nil { - fmt.Printf("error handling login response: %v\n", err) - return nil - } - } - defer resp.Body.Close() - if resp.StatusCode >= 400 { - buf, _ := ioutil.ReadAll(resp.Body) - fmt.Printf("interaction returned error status (%s): %s\n", resp.Status, buf) - } - return nil - } -} - -// SelectInteractiveLogin is a ResponseHandler that processes the list of -// login methods in the incoming response and performs a GET on that URL. -// If rh is non-nil it will be used to further process the response -// before returning to the caller. -func selectInteractiveLogin(rh responseHandler) responseHandler { - return func(client *http.Client, resp *http.Response) (*http.Response, error) { - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, errgo.Newf("unexpected status %q", resp.Status) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, errgo.Mask(err) - } - - // The body, as specified by the - // authenticationRequiredTemplate, will be a list of - // interactive login URLs, one on each line. Choose the - // first valid one. - - parts := bytes.Split(body, []byte("\n")) - lurl := "" - for _, p := range parts { - if len(p) == 0 { - continue - } - s := string(p) - if strings.Contains(s, "http://") { - s1 := strings.Split(s, "href=\"") - s2 := strings.Split(s1[1], "\"") - lurl = s2[0] - break - } - } - if lurl == "" { - return nil, errgo.New("login returned no URLs") - } - resp, err = client.Get(lurl) - if err != nil { - return resp, errgo.Mask(err) - } - if rh != nil { - resp, err = rh(client, resp) - } - return resp, errgo.Mask(err, errgo.Any) - } -} - -// LoginFormAction gets the action parameter (POST URL) of a login form. -func loginFormAction(resp *http.Response) (string, error) { - form := bufio.NewScanner(resp.Body) - for form.Scan() { - if strings.Contains(form.Text(), "http://") { - s1 := strings.Split(form.Text(), "action=\"") - s2 := strings.Split(s1[1], "\"") - return s2[0], nil - } - - } - return resp.Request.URL.String(), nil -} - -// PostLoginForm returns a ResponseHandler that can be passed to -// OpenWebBrowser which will complete a login form with the given -// Username and Password, and return the result. -func postLoginForm(username, password string) responseHandler { - return func(client *http.Client, resp *http.Response) (*http.Response, error) { - defer resp.Body.Close() - purl, err := loginFormAction(resp) - if err != nil { - return nil, errgo.Mask(err) - } - resp, err = client.PostForm(purl, url.Values{ - "username": {username}, - "password": {password}, - }) - return resp, errgo.Mask(err, errgo.Any) - } -} - -// authy -// A simple script to gather an initial macaroon on start to authenticate against JIMM with -// in a local environment. -func main() { - rpcclient, err := (&rpc.Dialer{}).Dial(context.TODO(), "ws://0.0.0.0:17070/api") - if err != nil { - log.Fatal("failed to dial controller:", err) - } - respres := jujuparams.LoginResult{} - - err = rpcclient.Call(context.Background(), "Admin", 3, "", "Login", nil, &respres) - if err != nil { - fmt.Println("failed to hit login facade:", err) - } - - macaroon := respres.BakeryDischargeRequired - - bakeryclient := httpbakery.NewClient() - - bakeryclient.AddInteractor(httpbakery.WebBrowserInteractor{ - OpenWebBrowser: openWebBrowser(selectInteractiveLogin(postLoginForm("jimm", "jimm"))), - }) - - discharged, err := bakeryclient.DischargeAll(context.TODO(), macaroon) - if err != nil { - fmt.Println("failed to discharge macaroons:", err) - } - - maccaroonieswoonies, _ := json.Marshal(discharged) - fmt.Println() - fmt.Println(string(maccaroonieswoonies)) - fmt.Println() - fmt.Println("Copy the macaroons, head to the JIMM postman collection and update your local collection variable for API_AUTH.") -} diff --git a/rocks/jimm.yaml b/rocks/jimm.yaml new file mode 100644 index 000000000..3a45f7c62 --- /dev/null +++ b/rocks/jimm.yaml @@ -0,0 +1,58 @@ +name: jimm +base: ubuntu@22.04 +version: '0.1' +summary: Juju Intelligent Model Manager provides a convient way to manage all of your models! +description: | + JIMM is a juju controller, used in conjunction with the JaaS dashboard to provide a seamless way + to manage models, regardless of where their controllers reside or what cloud they may be running on. + +license: GPL-3.0 +platforms: + amd64: + +services: + server: + summary: JIMM + description: | + JIMM is a juju controller, used in conjunction with the JaaS dashboard to provide a seamless way + to manage models, regardless of where their controllers reside or what cloud they may be running on. + startup: enabled + override: replace + command: jimmsrv + on-success: ignore + on-failure: restart + backoff-delay: 1s + backoff-factor: 2 + backoff-limit: 10s + kill-delay: 10s + +parts: + builder: + plugin: go # https://canonical-craft-parts--694.com.readthedocs.build/en/694/common/craft-parts/reference/plugins/go_plugin.html + source: . + source-type: local + build-snaps: + - go/1.22/stable + build-packages: + - git + - make + build-environment: + - GOOS: linux + override-build: | + set -ex + + mkdir -p $CRAFT_PART_INSTALL/usr/local/bin + + make build/server + cp ./jimmsrv $CRAFT_PART_INSTALL/usr/local/bin + + # The location of SQL files isn't configurable right now, as such we just + # place it in bin + cp -r ./internal/dbmodel/sql $CRAFT_PART_INSTALL/usr/local/bin/sql + + # Copied for the charm to collect and apply, not this container itself + mkdir -p $CRAFT_PART_INSTALL/root/openfga/ + cp ./openfga/authorisation_model.json $CRAFT_PART_INSTALL/root/openfga/authorisation_model.json + + stage-packages: + - ca-certificates \ No newline at end of file From a0cb00fdb34d7a0fd7ddb8ecd76c36cb08fbca4a Mon Sep 17 00:00:00 2001 From: ale8k Date: Wed, 12 Jun 2024 14:23:47 +0100 Subject: [PATCH 2/3] newline --- rocks/jimm.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocks/jimm.yaml b/rocks/jimm.yaml index 3a45f7c62..3ec4189a3 100644 --- a/rocks/jimm.yaml +++ b/rocks/jimm.yaml @@ -55,4 +55,4 @@ parts: cp ./openfga/authorisation_model.json $CRAFT_PART_INSTALL/root/openfga/authorisation_model.json stage-packages: - - ca-certificates \ No newline at end of file + - ca-certificates From 257f1ed24648f97c12ba67caccf2f426575dd7be Mon Sep 17 00:00:00 2001 From: ale8k Date: Thu, 13 Jun 2024 08:42:59 +0100 Subject: [PATCH 3/3] Update make help & s/juju/Juju --- Makefile | 2 ++ rocks/jimm.yaml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 0a225c8c7..d19e128bf 100644 --- a/Makefile +++ b/Makefile @@ -141,6 +141,8 @@ help: @echo 'make format - Format the source files.' @echo 'make simplify - Format and simplify the source files.' @echo 'make get-local-auth - Get local auth to the API WSS endpoint locally.' + @echo 'make rock - Build the JIMM rock.' + @echo 'make load-rock - Load the most recently built rock into your local docker daemon.' .PHONY: build check install release clean format server simplify sysdeps help FORCE diff --git a/rocks/jimm.yaml b/rocks/jimm.yaml index 3ec4189a3..8efc9ea79 100644 --- a/rocks/jimm.yaml +++ b/rocks/jimm.yaml @@ -3,7 +3,7 @@ base: ubuntu@22.04 version: '0.1' summary: Juju Intelligent Model Manager provides a convient way to manage all of your models! description: | - JIMM is a juju controller, used in conjunction with the JaaS dashboard to provide a seamless way + JIMM is a Juju controller, used in conjunction with the JaaS dashboard to provide a seamless way to manage models, regardless of where their controllers reside or what cloud they may be running on. license: GPL-3.0 @@ -14,7 +14,7 @@ services: server: summary: JIMM description: | - JIMM is a juju controller, used in conjunction with the JaaS dashboard to provide a seamless way + JIMM is a Juju controller, used in conjunction with the JaaS dashboard to provide a seamless way to manage models, regardless of where their controllers reside or what cloud they may be running on. startup: enabled override: replace