package main import ( "context" "fmt" garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang" "github.com/gorilla/mux" "log" "net/http" "strings" ) func gadmin() (*garage.APIClient, context.Context) { // Set Host and other parameters configuration := garage.NewConfiguration() configuration.Host = config.S3AdminEndpoint // We can now generate a client client := garage.NewAPIClient(configuration) // Authentication is handled through the context pattern ctx := context.WithValue(context.Background(), garage.ContextAccessToken, config.S3AdminToken) return client, ctx } func grgCreateKey(name string) (*garage.KeyInfo, error) { client, ctx := gadmin() kr := garage.AddKeyRequest{Name: &name} resp, _, err := client.KeyApi.AddKey(ctx).AddKeyRequest(kr).Execute() if err != nil { fmt.Printf("%+v\n", err) return nil, err } return resp, nil } func grgGetKey(accessKey string) (*garage.KeyInfo, error) { client, ctx := gadmin() resp, _, err := client.KeyApi.GetKey(ctx, accessKey).Execute() if err != nil { fmt.Printf("%+v\n", err) return nil, err } return resp, nil } func grgCreateBucket(bucket string) (*garage.BucketInfo, error) { client, ctx := gadmin() br := garage.NewCreateBucketRequest() br.SetGlobalAlias(bucket) // Create Bucket binfo, _, err := client.BucketApi.CreateBucket(ctx).CreateBucketRequest(*br).Execute() if err != nil { fmt.Printf("%+v\n", err) return nil, err } return binfo, nil } func grgAllowKeyOnBucket(bid, gkey string) (*garage.BucketInfo, error) { client, ctx := gadmin() // Allow user's key ar := garage.AllowBucketKeyRequest{ BucketId: bid, AccessKeyId: gkey, Permissions: *garage.NewAllowBucketKeyRequestPermissions(true, true, true), } binfo, _, err := client.BucketApi.AllowBucketKey(ctx).AllowBucketKeyRequest(ar).Execute() if err != nil { fmt.Printf("%+v\n", err) return nil, err } return binfo, nil } func allowWebsiteDefault() *garage.UpdateBucketRequestWebsiteAccess { wr := garage.NewUpdateBucketRequestWebsiteAccess() wr.SetEnabled(true) wr.SetIndexDocument("index.html") wr.SetErrorDocument("error.html") return wr } func grgUpdateBucket(bid string, ur *garage.UpdateBucketRequest) (*garage.BucketInfo, error) { client, ctx := gadmin() binfo, _, err := client.BucketApi.UpdateBucket(ctx, bid).UpdateBucketRequest(*ur).Execute() if err != nil { fmt.Printf("%+v\n", err) return nil, err } // Return updated binfo return binfo, nil } func grgAddGlobalAlias(bid, alias string) (*garage.BucketInfo, error) { client, ctx := gadmin() resp, _, err := client.BucketApi.PutBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute() if err != nil { log.Println(err) return nil, err } return resp, nil } func grgAddLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) { client, ctx := gadmin() resp, _, err := client.BucketApi.PutBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute() if err != nil { log.Println(err) return nil, err } return resp, nil } func grgDelGlobalAlias(bid, alias string) (*garage.BucketInfo, error) { client, ctx := gadmin() resp, _, err := client.BucketApi.DeleteBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute() if err != nil { log.Println(err) return nil, err } return resp, nil } func grgDelLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) { client, ctx := gadmin() resp, _, err := client.BucketApi.DeleteBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute() if err != nil { log.Println(err) return nil, err } return resp, nil } func grgGetBucket(bid string) (*garage.BucketInfo, error) { client, ctx := gadmin() resp, _, err := client.BucketApi.GetBucketInfo(ctx, bid).Execute() if err != nil { log.Println(err) return nil, err } return resp, nil } func grgDeleteBucket(bid string) error { client, ctx := gadmin() _, err := client.BucketApi.DeleteBucket(ctx, bid).Execute() if err != nil { log.Println(err) } return err } // --- Start page rendering functions func handleWebsiteConfigure(w http.ResponseWriter, r *http.Request) { user := RequireUserHtml(w, r) if user == nil { return } tKey := getTemplate("garage_key.html") tKey.Execute(w, user) } func handleWebsiteList(w http.ResponseWriter, r *http.Request) { user := RequireUserHtml(w, r) if user == nil { return } ctrl, err := NewWebsiteController(user) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if len(ctrl.PrettyList) > 0 { http.Redirect(w, r, "/website/inspect/"+ctrl.PrettyList[0], http.StatusFound) } else { http.Redirect(w, r, "/website/new", http.StatusFound) } } type WebsiteNewTpl struct { Ctrl *WebsiteController Err error } func handleWebsiteNew(w http.ResponseWriter, r *http.Request) { user := RequireUserHtml(w, r) if user == nil { return } ctrl, err := NewWebsiteController(user) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tpl := &WebsiteNewTpl{ctrl, nil} tWebsiteNew := getTemplate("garage_website_new.html") if r.Method == "POST" { r.ParseForm() bucket := strings.Join(r.Form["bucket"], "") if bucket == "" { bucket = strings.Join(r.Form["bucket2"], "") } view, err := ctrl.Create(bucket) if err != nil { tpl.Err = err tWebsiteNew.Execute(w, tpl) return } http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound) return } tWebsiteNew.Execute(w, tpl) } type WebsiteInspectTpl struct { Describe *WebsiteDescribe View *WebsiteView Err error } func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) { var processErr error user := RequireUserHtml(w, r) if user == nil { return } ctrl, err := NewWebsiteController(user) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } bucketName := mux.Vars(r)["bucket"] if r.Method == "POST" { r.ParseForm() action := strings.Join(r.Form["action"], "") switch action { case "increase_quota": _, processErr = ctrl.Patch(bucketName, &WebsitePatch{Size: &user.Quota.WebsiteSizeBursted}) case "delete_bucket": processErr = ctrl.Delete(bucketName) if processErr == nil { http.Redirect(w, r, "/website", http.StatusFound) } default: processErr = fmt.Errorf("Unknown action") } } view, err := ctrl.Inspect(bucketName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } describe, err := ctrl.Describe() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tpl := &WebsiteInspectTpl{describe, view, processErr} tWebsiteInspect := getTemplate("garage_website_inspect.html") tWebsiteInspect.Execute(w, &tpl) } func handleWebsiteVhost(w http.ResponseWriter, r *http.Request) { var processErr error user := RequireUserHtml(w, r) if user == nil { return } ctrl, err := NewWebsiteController(user) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } bucketName := mux.Vars(r)["bucket"] if r.Method == "POST" { r.ParseForm() bucket := strings.Join(r.Form["bucket"], "") if bucket == "" { bucket = strings.Join(r.Form["bucket2"], "") } view, processErr := ctrl.Patch(bucketName, &WebsitePatch{Vhost: &bucket}) if processErr == nil { http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound) return } } view, err := ctrl.Inspect(bucketName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } describe, err := ctrl.Describe() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } tpl := &WebsiteInspectTpl{describe, view, processErr} tWebsiteEdit := getTemplate("garage_website_edit.html") tWebsiteEdit.Execute(w, &tpl) }