Skip to content
Merged
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
93 changes: 68 additions & 25 deletions cmd/rofl/deploy.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package rofl

import (
"bytes"
"context"
"errors"
"fmt"
"maps"
"os"
"sort"

"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
Expand All @@ -27,12 +29,13 @@ import (
)

var (
deployProvider string
deployOffer string
deployMachine string
deployTerm string
deployTermCount uint64
deployForce bool
deployProvider string
deployOffer string
deployMachine string
deployTerm string
deployTermCount uint64
deployForce bool
deployShowOffers bool

deployCmd = &cobra.Command{
Use: "deploy",
Expand Down Expand Up @@ -106,10 +109,10 @@ var (

fmt.Printf("Using provider: %s (%s)\n", machine.Provider, providerAddr)

// Parse machine payment term.
term := roflCommon.ParseMachineTerm(deployTerm)
if deployTermCount < 1 {
cobra.CheckErr("Number of terms must be at least 1.")
if deployShowOffers {
// Display all offers supported by the provider.
showProviderOffers(ctx, npa, conn, *providerAddr)
return
}

// Push ORC to OCI repository.
Expand Down Expand Up @@ -143,24 +146,17 @@ var (
// When machine is not set, we need to obtain one.
fmt.Printf("No pre-existing machine configured, creating a new one...\n")

if machine.Offer == "" && deployOffer == "" {
// Display all offers supported by the provider.
showProviderOffers(ctx, npa, conn, *providerAddr)
cobra.CheckErr(fmt.Sprintf("Offer not configured for deployment '%s' machine '%s'. Please specify --offer.", deploymentName, deployMachine))
}
if deployOffer != "" {
machine.Offer = deployOffer
}

// Resolve offer.
var offers []*roflmarket.Offer
offers, err = conn.Runtime(npa.ParaTime).ROFLMarket.Offers(ctx, client.RoundLatest, *providerAddr)
if err != nil {
cobra.CheckErr(fmt.Sprintf("Failed to query provider: %s", err))
}
offers, err := fetchProviderOffers(ctx, npa, conn, *providerAddr)
cobra.CheckErr(err)
var offer *roflmarket.Offer
for _, of := range offers {
if of.Metadata[provider.SchedulerMetadataOfferKey] == machine.Offer {
if of.Metadata[provider.SchedulerMetadataOfferKey] == machine.Offer || machine.Offer == "" {
Comment thread
matevz marked this conversation as resolved.
machine.Offer = of.Metadata[provider.SchedulerMetadataOfferKey]
offer = of
break
}
Expand All @@ -173,6 +169,11 @@ var (

fmt.Printf("Taking offer: %s [%s]\n", machine.Offer, offer.ID)

term := detectTerm(offer)
if deployTermCount < 1 {
cobra.CheckErr("Number of terms must be at least 1.")
}

// Prepare transaction.
tx := roflmarket.NewInstanceCreateTx(nil, &roflmarket.InstanceCreate{
Provider: *providerAddr,
Expand Down Expand Up @@ -249,11 +250,51 @@ var (
}
)

func showProviderOffers(ctx context.Context, npa *common.NPASelection, conn connection.Connection, provider types.Address) {
offers, err := conn.Runtime(npa.ParaTime).ROFLMarket.Offers(ctx, client.RoundLatest, provider)
// detectTerm returns the preferred (longest) period of the given offer.
func detectTerm(offer *roflmarket.Offer) (term roflmarket.Term) {
if offer == nil {
cobra.CheckErr(fmt.Errorf("no offers exist to determine payment term"))
return // Linter complains otherwise.
}
if offer.Payment.Native == nil {
cobra.CheckErr(fmt.Errorf("no payment terms available for offer '%s'", offer.ID))
}

if deployTerm != "" {
// Custom deploy term.
term = roflCommon.ParseMachineTerm(deployTerm)
if _, ok := offer.Payment.Native.Terms[term]; !ok {
cobra.CheckErr(fmt.Errorf("term '%s' is not available for offer '%s'", deployTerm, offer.ID))
}
return
}

// Take the longest payment period.
// TODO: Sort by actual periods (e.g. seconds) instead of internal roflmarket.Term index.
for t := range offer.Payment.Native.Terms {
if t > term {
Comment thread
matevz marked this conversation as resolved.
term = t
}
}
return
}

func fetchProviderOffers(ctx context.Context, npa *common.NPASelection, conn connection.Connection, provider types.Address) (offers []*roflmarket.Offer, err error) {
offers, err = conn.Runtime(npa.ParaTime).ROFLMarket.Offers(ctx, client.RoundLatest, provider)
if err != nil {
err = fmt.Errorf("failed to query provider: %s", err)
return
}
// Order offers, newer first.
sort.Slice(offers, func(i, j int) bool {
return bytes.Compare(offers[i].ID[:], offers[j].ID[:]) > 0
})
return
}

func showProviderOffers(ctx context.Context, npa *common.NPASelection, conn connection.Connection, provider types.Address) {
offers, err := fetchProviderOffers(ctx, npa, conn, provider)
cobra.CheckErr(err)

fmt.Println()
fmt.Printf("Offers available from the selected provider:\n")
Expand Down Expand Up @@ -295,12 +336,14 @@ func showProviderOffer(offer *roflmarket.Offer) {

func init() {
providerFlags := flag.NewFlagSet("", flag.ContinueOnError)
providerFlags.StringVar(&deployProvider, "provider", "", "set the provider address")
// Default to Testnet playground provider.
providerFlags.StringVar(&deployProvider, "provider", "oasis1qp2ens0hsp7gh23wajxa4hpetkdek3swyyulyrmz", "set the provider address")
providerFlags.StringVar(&deployOffer, "offer", "", "set the provider's offer identifier")
providerFlags.StringVar(&deployMachine, "machine", buildRofl.DefaultMachineName, "machine to deploy into")
providerFlags.StringVar(&deployTerm, "term", roflCommon.TermMonth, "term to pay for in advance")
providerFlags.StringVar(&deployTerm, "term", "", "term to pay for in advance")
providerFlags.Uint64Var(&deployTermCount, "term-count", 1, "number of terms to pay for in advance")
providerFlags.BoolVar(&deployForce, "force", false, "force deployment")
providerFlags.BoolVar(&deployShowOffers, "show-offers", false, "show all provider offers and quit")

deployCmd.Flags().AddFlagSet(common.SelectorFlags)
deployCmd.Flags().AddFlagSet(common.RuntimeTxFlags)
Expand Down
Loading