diff --git a/_run/common-commands.mk b/_run/common-commands.mk index 7bc16654..1afeecaa 100644 --- a/_run/common-commands.mk +++ b/_run/common-commands.mk @@ -82,6 +82,14 @@ send-manifest: --from "$(KEY_NAME)" \ --provider "$(PROVIDER_ADDRESS)" +.PHONY: get-manifest +get-manifest: + $(PROVIDER_SERVICES) get-manifest \ + --dseq "$(DSEQ)" \ + --from "$(KEY_NAME)" \ + --provider "$(PROVIDER_ADDRESS)" + + .PHONY: deployment-create deployment-create: $(AKASH) tx deployment create "$(SDL_PATH)" \ diff --git a/cmd/provider-services/cmd/helpers.go b/cmd/provider-services/cmd/helpers.go index 173ec0ba..397b79b2 100644 --- a/cmd/provider-services/cmd/helpers.go +++ b/cmd/provider-services/cmd/helpers.go @@ -80,6 +80,41 @@ func dseqFromFlags(flags *pflag.FlagSet) (uint64, error) { return flags.GetUint64(FlagDSeq) } +func leaseIDFromFlags(cflags *pflag.FlagSet, owner string) (mtypes.LeaseID, error) { + str, err := cflags.GetString(FlagProvider) + if err != nil { + return mtypes.LeaseID{}, err + } + + provider, err := sdk.AccAddressFromBech32(str) + if err != nil { + return mtypes.LeaseID{}, err + } + + dseq, err := cflags.GetUint64(FlagDSeq) + if err != nil { + return mtypes.LeaseID{}, err + } + + gseq, err := cflags.GetUint32(FlagGSeq) + if err != nil { + return mtypes.LeaseID{}, err + } + + oseq, err := cflags.GetUint32(FlagOSeq) + if err != nil { + return mtypes.LeaseID{}, err + } + + return mtypes.LeaseID{ + Owner: owner, + DSeq: dseq, + GSeq: gseq, + OSeq: oseq, + Provider: provider.String(), + }, nil +} + func providerFromFlags(flags *pflag.FlagSet) (sdk.Address, error) { provider, err := flags.GetString(FlagProvider) if err != nil { diff --git a/cmd/provider-services/cmd/manifest.go b/cmd/provider-services/cmd/manifest.go index 79147623..91de6c4e 100644 --- a/cmd/provider-services/cmd/manifest.go +++ b/cmd/provider-services/cmd/manifest.go @@ -25,6 +25,13 @@ var ( errSubmitManifestFailed = errors.New("submit manifest to some providers has been failed") ) +func ManifestCmds() []*cobra.Command { + return []*cobra.Command{ + SendManifestCmd(), + GetManifestCmd(), + } +} + // SendManifestCmd looks up the Providers blockchain information, // and POSTs the SDL file to the Gateway address. func SendManifestCmd() *cobra.Command { @@ -45,6 +52,77 @@ func SendManifestCmd() *cobra.Command { return cmd } +// GetManifestCmd reads current manifest from the provider +func GetManifestCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "get-manifest", + Args: cobra.ExactArgs(0), + Short: "Read manifest from provider", + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + cctx, err := sdkclient.GetClientTxContext(cmd) + if err != nil { + return err + } + + ctx := cmd.Context() + + cl, err := aclient.DiscoverQueryClient(ctx, cctx) + if err != nil { + return err + } + + cert, err := cutils.LoadAndQueryCertificateForAccount(cmd.Context(), cctx, nil) + if err != nil { + return markRPCServerError(err) + } + + lid, err := leaseIDFromFlags(cmd.Flags(), cctx.GetFromAddress().String()) + if err != nil { + return err + } + + prov, _ := sdk.AccAddressFromBech32(lid.Provider) + gclient, err := gwrest.NewClient(ctx, cl, prov, []tls.Certificate{cert}) + if err != nil { + return err + } + + mani, err := gclient.GetManifest(ctx, lid) + if err != nil { + return err + } + + buf := &bytes.Buffer{} + + switch cmd.Flag(flagOutput).Value.String() { + case outputJSON: + err = json.NewEncoder(buf).Encode(mani) + case outputYAML: + err = yaml.NewEncoder(buf).Encode(mani) + } + + if err != nil { + return err + } + + _, err = fmt.Fprint(cmd.OutOrStdout(), buf.String()) + + if err != nil { + return err + } + + return nil + }, + } + + addLeaseFlags(cmd) + + cmd.Flags().StringP(flagOutput, "o", outputYAML, "output format json|yaml. default yaml") + + return cmd +} + func doSendManifest(cmd *cobra.Command, sdlpath string) error { cctx, err := sdkclient.GetClientTxContext(cmd) if err != nil { diff --git a/cmd/provider-services/cmd/root.go b/cmd/provider-services/cmd/root.go index 1d11f96f..e7611458 100644 --- a/cmd/provider-services/cmd/root.go +++ b/cmd/provider-services/cmd/root.go @@ -39,7 +39,7 @@ func NewRootCmd() *cobra.Command { return nil } - cmd.AddCommand(SendManifestCmd()) + cmd.AddCommand(ManifestCmds()...) cmd.AddCommand(statusCmd()) cmd.AddCommand(leaseStatusCmd()) cmd.AddCommand(leaseEventsCmd()) diff --git a/gateway/rest/client.go b/gateway/rest/client.go index f3439167..1862b2cf 100644 --- a/gateway/rest/client.go +++ b/gateway/rest/client.go @@ -48,6 +48,7 @@ type Client interface { Status(ctx context.Context) (*provider.Status, error) Validate(ctx context.Context, gspec dtypes.GroupSpec) (provider.ValidateGroupSpecResult, error) SubmitManifest(ctx context.Context, dseq uint64, mani manifest.Manifest) error + GetManifest(ctx context.Context, id mtypes.LeaseID) (manifest.Manifest, error) LeaseStatus(ctx context.Context, id mtypes.LeaseID) (LeaseStatus, error) LeaseEvents(ctx context.Context, id mtypes.LeaseID, services string, follow bool) (*LeaseKubeEvents, error) LeaseLogs(ctx context.Context, id mtypes.LeaseID, services string, follow bool, tailLines int64) (*ServiceLogs, error) @@ -425,6 +426,46 @@ func (c *client) SubmitManifest(ctx context.Context, dseq uint64, mani manifest. return createClientResponseErrorIfNotOK(resp, responseBuf) } +func (c *client) GetManifest(ctx context.Context, lid mtypes.LeaseID) (manifest.Manifest, error) { + uri, err := makeURI(c.host, getManifestPath(lid)) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, "GET", uri, nil) + if err != nil { + return nil, err + } + + rCl := c.newReqClient(ctx) + resp, err := rCl.hclient.Do(req) + + if err != nil { + return nil, err + } + + defer func() { + _ = resp.Body.Close() + }() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = createClientResponseErrorIfNotOK(resp, bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + + var mani manifest.Manifest + if err = json.Unmarshal(body, &mani); err != nil { + return nil, err + } + + return mani, nil +} + func (c *client) MigrateEndpoints(ctx context.Context, endpoints []string, dseq uint64, gseq uint32) error { uri, err := makeURI(c.host, "endpoint/migrate") if err != nil { diff --git a/gateway/rest/path.go b/gateway/rest/path.go index 175b6769..9126d3d6 100644 --- a/gateway/rest/path.go +++ b/gateway/rest/path.go @@ -34,6 +34,10 @@ func submitManifestPath(dseq uint64) string { return fmt.Sprintf("deployment/%d/manifest", dseq) } +func getManifestPath(id mtypes.LeaseID) string { + return fmt.Sprintf("%s/manifest", leasePath(id)) +} + func leaseStatusPath(id mtypes.LeaseID) string { return fmt.Sprintf("%s/status", leasePath(id)) } diff --git a/gateway/rest/router.go b/gateway/rest/router.go index 8b19606c..4e91c291 100644 --- a/gateway/rest/router.go +++ b/gateway/rest/router.go @@ -127,21 +127,23 @@ func newRouter(log log.Logger, addr sdk.Address, pclient provider.Client, ctxCon hostnameRouter := router.PathPrefix(hostnamePrefix).Subrouter() hostnameRouter.Use(requireOwner()) - hostnameRouter.HandleFunc(migratePathPrefix, migrateHandler(log, pclient.Hostname(), pclient.ClusterService())). + hostnameRouter.HandleFunc(migratePathPrefix, + migrateHandler(log, pclient.Hostname(), pclient.ClusterService())). Methods(http.MethodPost) endpointRouter := router.PathPrefix(endpointPrefix).Subrouter() endpointRouter.Use(requireOwner()) - endpointRouter.HandleFunc(migratePathPrefix, migrateEndpointHandler(log, pclient.ClusterService(), pclient.Cluster())). + endpointRouter.HandleFunc(migratePathPrefix, + migrateEndpointHandler(log, pclient.ClusterService(), pclient.Cluster())). Methods(http.MethodPost) - // PUT /deployment/manifest drouter := router.PathPrefix(deploymentPathPrefix).Subrouter() drouter.Use( requireOwner(), requireDeploymentID(), ) + // PUT /deployment/manifest drouter.HandleFunc("/manifest", createManifestHandler(log, pclient.Manifest())). Methods(http.MethodPut) @@ -152,6 +154,11 @@ func newRouter(log log.Logger, addr sdk.Address, pclient provider.Client, ctxCon requireLeaseID(), ) + // GET /lease//manifest + lrouter.HandleFunc("/manifest", + getManifestHandler(log, pclient.Cluster())). + Methods(http.MethodGet) + // GET /lease//status lrouter.HandleFunc("/status", leaseStatusHandler(log, pclient.Cluster(), ctxConfig)). @@ -188,7 +195,7 @@ func newRouter(log log.Logger, addr sdk.Address, pclient provider.Client, ctxCon // POST /lease//shell lrouter.HandleFunc("/shell", - leaseShellHandler(log, pclient.Manifest(), pclient.Cluster())) + leaseShellHandler(log, pclient.Cluster())) return router } @@ -306,7 +313,7 @@ type leaseShellResponse struct { Message string `json:"message,omitempty"` } -func leaseShellHandler(log log.Logger, mclient pmanifest.Client, cclient cluster.Client) http.HandlerFunc { +func leaseShellHandler(log log.Logger, cclient cluster.Client) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { leaseID := requestLeaseID(req) @@ -591,6 +598,29 @@ func createManifestHandler(log log.Logger, mclient pmanifest.Client) http.Handle } } +func getManifestHandler(log log.Logger, cclient cluster.ReadClient) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + found, grp, err := cclient.GetManifestGroup(r.Context(), requestLeaseID(r)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if !found { + http.Error(w, "lease not found", http.StatusNotFound) + return + } + + mgrp, _, err := grp.FromCRD() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + writeJSON(log, w, &manifest.Manifest{mgrp}) + } +} + func leaseKubeEventsHandler(log log.Logger, cclient cluster.ReadClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { upgrader := websocket.Upgrader{ diff --git a/pkg/apis/akash.network/v2beta2/manifest.go b/pkg/apis/akash.network/v2beta2/manifest.go index d1b5681f..b08c6a4e 100644 --- a/pkg/apis/akash.network/v2beta2/manifest.go +++ b/pkg/apis/akash.network/v2beta2/manifest.go @@ -171,7 +171,7 @@ func (m *Manifest) Deployment() (ctypes.IDeployment, error) { return nil, err } - group, schedulerParams, err := m.Spec.Group.fromCRD() + group, schedulerParams, err := m.Spec.Group.FromCRD() if err != nil { return nil, err } @@ -185,8 +185,8 @@ func (m *Manifest) Deployment() (ctypes.IDeployment, error) { }, nil } -// toAkash returns akash group details formatted from manifest group -func (m *ManifestGroup) fromCRD() (mani.Group, []*SchedulerParams, error) { +// FromCRD returns akash group details formatted from manifest group +func (m *ManifestGroup) FromCRD() (mani.Group, []*SchedulerParams, error) { am := mani.Group{ Name: m.Name, Services: make([]mani.Service, 0, len(m.Services)),