From 5d8e97dadfb0e0721f1d6835677c905de9c6882f Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Tue, 14 Jan 2025 09:42:13 +0100 Subject: [PATCH] feat(cmd/rofl): Add support for multiple deployments --- build/rofl/manifest.go | 72 ++++++++++++++++++++++++---------- build/rofl/manifest_test.go | 77 +++++++++++++++++++++++++------------ cmd/rofl/build/build.go | 47 ++++++++++++---------- cmd/rofl/build/container.go | 12 ++++-- cmd/rofl/build/sgx.go | 13 +++++-- cmd/rofl/build/tdx.go | 19 ++++++--- cmd/rofl/common/manifest.go | 45 ++++++++++++---------- cmd/rofl/mgmt.go | 65 ++++++++++++++++++++----------- 8 files changed, 229 insertions(+), 121 deletions(-) diff --git a/build/rofl/manifest.go b/build/rofl/manifest.go index 94dcb0c..d4d9487 100644 --- a/build/rofl/manifest.go +++ b/build/rofl/manifest.go @@ -34,31 +34,21 @@ const ( // Manifest is the ROFL app manifest that configures various aspects of the app in a single place. type Manifest struct { - // AppID is the Bech32-encoded ROFL app ID. - AppID string `yaml:"app_id" json:"app_id"` // Name is the human readable ROFL app name. Name string `yaml:"name" json:"name"` // Version is the ROFL app version. Version string `yaml:"version" json:"version"` - // Network is the identifier of the network to deploy to by default. - Network string `yaml:"network,omitempty" json:"network,omitempty"` - // ParaTime is the identifier of the paratime to deploy to by default. - ParaTime string `yaml:"paratime,omitempty" json:"paratime,omitempty"` - // Admin is the identifier of the admin account. - Admin string `yaml:"admin,omitempty" json:"admin,omitempty"` // TEE is the type of TEE to build for. TEE string `yaml:"tee" json:"tee"` // Kind is the kind of ROFL app to build. Kind string `yaml:"kind" json:"kind"` - // TrustRoot is the optional trust root configuration. - TrustRoot *TrustRootConfig `yaml:"trust_root,omitempty" json:"trust_root,omitempty"` // Resources are the requested ROFL app resources. Resources ResourcesConfig `yaml:"resources" json:"resources"` // Artifacts are the optional artifact location overrides. Artifacts *ArtifactsConfig `yaml:"artifacts,omitempty" json:"artifacts,omitempty"` - // Policy is the ROFL app policy to deploy by default. - Policy *rofl.AppAuthPolicy `yaml:"policy,omitempty" json:"policy,omitempty"` + // Deployments are the ROFL app deployments. + Deployments map[string]*Deployment `yaml:"deployments" json:"deployments"` // sourceFn is the filename from which the manifest has been loaded. sourceFn string @@ -111,14 +101,6 @@ func LoadManifest() (*Manifest, error) { // Validate validates the manifest for correctness. func (m *Manifest) Validate() error { - if len(m.AppID) == 0 { - return fmt.Errorf("app ID cannot be empty") - } - var appID rofl.AppID - if err := appID.UnmarshalText([]byte(m.AppID)); err != nil { - return fmt.Errorf("malformed app ID: %w", err) - } - if len(m.Name) == 0 { return fmt.Errorf("name cannot be empty") } @@ -150,6 +132,18 @@ func (m *Manifest) Validate() error { return fmt.Errorf("bad resources config: %w", err) } + for name, d := range m.Deployments { + if d == nil { + return fmt.Errorf("bad deployment: %s", name) + } + if err := d.Validate(); err != nil { + return fmt.Errorf("bad deployment '%s': %w", name, err) + } + } + if _, ok := m.Deployments[DefaultDeploymentName]; !ok { + return fmt.Errorf("must define at least the '%s' deployment", DefaultDeploymentName) + } + return nil } @@ -159,6 +153,44 @@ func (m *Manifest) SourceFileName() string { return m.sourceFn } +// DefaultDeploymentName is the name of the default deployment that must always be defined and is +// used in case no deployment is passed. +const DefaultDeploymentName = "default" + +// Deployment describes a single ROFL app deployment. +type Deployment struct { + // AppID is the Bech32-encoded ROFL app ID. + AppID string `yaml:"app_id" json:"app_id"` + // Network is the identifier of the network to deploy to. + Network string `yaml:"network" json:"network"` + // ParaTime is the identifier of the paratime to deploy to. + ParaTime string `yaml:"paratime" json:"paratime"` + // Admin is the identifier of the admin account. + Admin string `yaml:"admin,omitempty" json:"admin,omitempty"` + // TrustRoot is the optional trust root configuration. + TrustRoot *TrustRootConfig `yaml:"trust_root,omitempty" json:"trust_root,omitempty"` + // Policy is the ROFL app policy. + Policy *rofl.AppAuthPolicy `yaml:"policy,omitempty" json:"policy,omitempty"` +} + +// Validate validates the manifest for correctness. +func (d *Deployment) Validate() error { + if len(d.AppID) == 0 { + return fmt.Errorf("app ID cannot be empty") + } + var appID rofl.AppID + if err := appID.UnmarshalText([]byte(d.AppID)); err != nil { + return fmt.Errorf("malformed app ID: %w", err) + } + if d.Network == "" { + return fmt.Errorf("network cannot be empty") + } + if d.ParaTime == "" { + return fmt.Errorf("paratime cannot be empty") + } + return nil +} + // TrustRootConfig is the trust root configuration. type TrustRootConfig struct { // Height is the consensus layer block height where to take the trust root. diff --git a/build/rofl/manifest_test.go b/build/rofl/manifest_test.go index 86d3d21..ec66e23 100644 --- a/build/rofl/manifest_test.go +++ b/build/rofl/manifest_test.go @@ -15,16 +15,6 @@ func TestManifestValidation(t *testing.T) { // Empty manifest is not valid. m := Manifest{} err := m.Validate() - require.ErrorContains(err, "app ID cannot be empty") - - // Invalid app ID. - m.AppID = "foo" - err = m.Validate() - require.ErrorContains(err, "malformed app ID") - - // Empty name. - m.AppID = "rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j" - err = m.Validate() require.ErrorContains(err, "name cannot be empty") // Empty version. @@ -33,7 +23,7 @@ func TestManifestValidation(t *testing.T) { require.ErrorContains(err, "version cannot be empty") // Invalid version. - m.Version = "foo" + m.Version = "invalidversion" err = m.Validate() require.ErrorContains(err, "malformed version") @@ -61,27 +51,53 @@ func TestManifestValidation(t *testing.T) { err = m.Validate() require.ErrorContains(err, "bad resources config: vCPU count must be at least 1") - // Finally, everything is valid. + // No default deployment. m.Resources.CPUCount = 1 err = m.Validate() + require.ErrorContains(err, "must define at least the 'default' deployment") + + // Missing app ID in deployment. + m.Deployments = map[string]*Deployment{ + "default": {}, + } + err = m.Validate() + require.ErrorContains(err, "bad deployment 'default': app ID cannot be empty") + + // Invalid app ID. + m.Deployments["default"].AppID = "foo" + err = m.Validate() + require.ErrorContains(err, "bad deployment 'default': malformed app ID") + + // Missing network in deployment. + m.Deployments["default"].AppID = "rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j" + err = m.Validate() + require.ErrorContains(err, "bad deployment 'default': network cannot be empty") + + // Missing paratime in deployment. + m.Deployments["default"].Network = "foo" + err = m.Validate() + require.ErrorContains(err, "bad deployment 'default': paratime cannot be empty") + + // Finally, everything is valid. + m.Deployments["default"].ParaTime = "bar" + err = m.Validate() require.NoError(err) // Add ephemeral storage configuration. - m.Resources.EphemeralStorage = &EphemeralStorageConfig{} + m.Resources.Storage = &StorageConfig{} err = m.Validate() - require.ErrorContains(err, "bad resources config: bad ephemeral storage config: unsupported ephemeral storage kind") + require.ErrorContains(err, "bad resources config: bad storage config: unsupported storage kind") - m.Resources.EphemeralStorage.Kind = "ram" + m.Resources.Storage.Kind = "ram" err = m.Validate() - require.ErrorContains(err, "bad resources config: bad ephemeral storage config: ephemeral storage size must be at least 16M") + require.ErrorContains(err, "bad resources config: bad storage config: storage size must be at least 16M") - m.Resources.EphemeralStorage.Size = 16 + m.Resources.Storage.Size = 16 err = m.Validate() require.NoError(err) } const serializedYamlManifest = ` -app_id: rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j name: my-simple-app version: 0.1.0 tee: tdx @@ -89,9 +105,14 @@ kind: container resources: memory: 16 cpus: 1 - ephemeral_storage: + storage: kind: ram size: 16 +deployments: + default: + app_id: rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j + network: foo + paratime: bar ` func TestManifestSerialization(t *testing.T) { @@ -102,16 +123,18 @@ func TestManifestSerialization(t *testing.T) { require.NoError(err, "yaml.Unmarshal") err = m.Validate() require.NoError(err, "m.Validate") - require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.AppID) require.Equal("my-simple-app", m.Name) require.Equal("0.1.0", m.Version) require.Equal("tdx", m.TEE) require.Equal("container", m.Kind) require.EqualValues(16, m.Resources.Memory) require.EqualValues(1, m.Resources.CPUCount) - require.NotNil(m.Resources.EphemeralStorage) - require.Equal("ram", m.Resources.EphemeralStorage.Kind) - require.EqualValues(16, m.Resources.EphemeralStorage.Size) + require.NotNil(m.Resources.Storage) + require.Equal("ram", m.Resources.Storage.Kind) + require.EqualValues(16, m.Resources.Storage.Size) + require.Len(m.Deployments, 1) + require.Contains(m.Deployments, "default") + require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.Deployments["default"].AppID) enc, err := yaml.Marshal(m) require.NoError(err, "yaml.Marshal") @@ -147,7 +170,9 @@ func TestLoadManifest(t *testing.T) { require.NoError(err) m, err := LoadManifest() require.NoError(err) - require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.AppID) + require.Len(m.Deployments, 1) + require.Contains(m.Deployments, "default") + require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.Deployments["default"].AppID) err = os.Remove(manifestFn) require.NoError(err) @@ -157,5 +182,7 @@ func TestLoadManifest(t *testing.T) { require.NoError(err) m, err = LoadManifest() require.NoError(err) - require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.AppID) + require.Len(m.Deployments, 1) + require.Contains(m.Deployments, "default") + require.Equal("rofl1qpa9ydy3qmka3yrqzx0pxuvyfexf9mlh75hker5j", m.Deployments["default"].AppID) } diff --git a/cmd/rofl/build/build.go b/cmd/rofl/build/build.go index 9579163..cf341a2 100644 --- a/cmd/rofl/build/build.go +++ b/cmd/rofl/build/build.go @@ -32,10 +32,11 @@ const ( ) var ( - outputFn string - buildMode string - offline bool - doUpdate bool + outputFn string + buildMode string + offline bool + doUpdate bool + deploymentName string Cmd = &cobra.Command{ Use: "build", @@ -44,14 +45,17 @@ var ( Run: func(_ *cobra.Command, _ []string) { cfg := cliConfig.Global() npa := common.GetNPASelection(cfg) - manifest := roflCommon.LoadManifestAndSetNPA(cfg, npa) + manifest, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName) fmt.Println("Building a ROFL application...") - fmt.Printf("App ID: %s\n", manifest.AppID) - fmt.Printf("Name: %s\n", manifest.Name) - fmt.Printf("Version: %s\n", manifest.Version) - fmt.Printf("TEE: %s\n", manifest.TEE) - fmt.Printf("Kind: %s\n", manifest.Kind) + fmt.Printf("Deployment: %s\n", deploymentName) + fmt.Printf("Network: %s\n", deployment.Network) + fmt.Printf("ParaTime: %s\n", deployment.ParaTime) + fmt.Printf("App ID: %s\n", deployment.AppID) + fmt.Printf("Name: %s\n", manifest.Name) + fmt.Printf("Version: %s\n", manifest.Version) + fmt.Printf("TEE: %s\n", manifest.TEE) + fmt.Printf("Kind: %s\n", manifest.Kind) // Prepare temporary build directory. tmpDir, err := os.MkdirTemp("", "oasis-build") @@ -62,7 +66,7 @@ var ( bnd := &bundle.Bundle{ Manifest: &bundle.Manifest{ - Name: manifest.AppID, + Name: deployment.AppID, ID: npa.ParaTime.Namespace(), }, } @@ -80,14 +84,14 @@ var ( return } - sgxBuild(npa, manifest, bnd) + sgxBuild(npa, manifest, deployment, bnd) case buildRofl.TEETypeTDX: // TDX. switch manifest.Kind { case buildRofl.AppKindRaw: - err = tdxBuildRaw(tmpDir, npa, manifest, bnd) + err = tdxBuildRaw(tmpDir, npa, manifest, deployment, bnd) case buildRofl.AppKindContainer: - err = tdxBuildContainer(tmpDir, npa, manifest, bnd) + err = tdxBuildContainer(tmpDir, npa, manifest, deployment, bnd) } default: fmt.Printf("unsupported TEE kind: %s\n", manifest.TEE) @@ -99,7 +103,7 @@ var ( } // Write the bundle out. - outFn := fmt.Sprintf("%s.orc", manifest.Name) + outFn := fmt.Sprintf("%s.%s.orc", manifest.Name, deploymentName) if outputFn != "" { outFn = outputFn } @@ -119,7 +123,7 @@ var ( } // Override the update manifest flag in case the policy does not exist. - if manifest.Policy == nil { + if deployment.Policy == nil { doUpdate = false } @@ -135,9 +139,9 @@ var ( fmt.Println() case true: // Update the manifest with the given enclave identities, overwriting existing ones. - manifest.Policy.Enclaves = make([]sgx.EnclaveIdentity, 0, len(eids)) + deployment.Policy.Enclaves = make([]sgx.EnclaveIdentity, 0, len(eids)) for _, eid := range eids { - manifest.Policy.Enclaves = append(manifest.Policy.Enclaves, *eid) + deployment.Policy.Enclaves = append(deployment.Policy.Enclaves, *eid) } // Serialize manifest and write it to file. @@ -173,12 +177,12 @@ func detectBuildMode(npa *common.NPASelection) { } } -func setupBuildEnv(manifest *buildRofl.Manifest, npa *common.NPASelection) { +func setupBuildEnv(deployment *buildRofl.Deployment, npa *common.NPASelection) { // Configure app ID. - os.Setenv("ROFL_APP_ID", manifest.AppID) + os.Setenv("ROFL_APP_ID", deployment.AppID) // Obtain and configure trust root. - trustRoot, err := fetchTrustRoot(npa, manifest.TrustRoot) + trustRoot, err := fetchTrustRoot(npa, deployment.TrustRoot) cobra.CheckErr(err) os.Setenv("ROFL_CONSENSUS_TRUST_ROOT", trustRoot) } @@ -250,6 +254,7 @@ func init() { buildFlags.BoolVar(&offline, "offline", false, "do not perform any operations requiring network access") buildFlags.StringVar(&outputFn, "output", "", "output bundle filename") buildFlags.BoolVar(&doUpdate, "update-manifest", false, "automatically update the manifest") + buildFlags.StringVar(&deploymentName, "deployment", buildRofl.DefaultDeploymentName, "deployment name") Cmd.Flags().AddFlagSet(buildFlags) } diff --git a/cmd/rofl/build/container.go b/cmd/rofl/build/container.go index 28e760c..e699166 100644 --- a/cmd/rofl/build/container.go +++ b/cmd/rofl/build/container.go @@ -21,7 +21,13 @@ const ( ) // tdxBuildContainer builds a TDX-based container ROFL app. -func tdxBuildContainer(tmpDir string, npa *common.NPASelection, manifest *buildRofl.Manifest, bnd *bundle.Bundle) error { +func tdxBuildContainer( + tmpDir string, + npa *common.NPASelection, + manifest *buildRofl.Manifest, + deployment *buildRofl.Deployment, + bnd *bundle.Bundle, +) error { fmt.Println("Building a container-based TDX ROFL application...") tdxStage2TemplateURI = defaultContainerStage2TemplateURI @@ -54,11 +60,11 @@ func tdxBuildContainer(tmpDir string, npa *common.NPASelection, manifest *buildR // Configure app ID. var extraKernelOpts []string extraKernelOpts = append(extraKernelOpts, - fmt.Sprintf("ROFL_APP_ID=%s", manifest.AppID), + fmt.Sprintf("ROFL_APP_ID=%s", deployment.AppID), ) // Obtain and configure trust root. - trustRoot, err := fetchTrustRoot(npa, manifest.TrustRoot) + trustRoot, err := fetchTrustRoot(npa, deployment.TrustRoot) if err != nil { return err } diff --git a/cmd/rofl/build/sgx.go b/cmd/rofl/build/sgx.go index f4ab719..5bb1747 100644 --- a/cmd/rofl/build/sgx.go +++ b/cmd/rofl/build/sgx.go @@ -24,11 +24,16 @@ import ( ) // sgxBuild builds an SGX-based "raw" ROFL app. -func sgxBuild(npa *common.NPASelection, manifest *buildRofl.Manifest, bnd *bundle.Bundle) { +func sgxBuild( + npa *common.NPASelection, + manifest *buildRofl.Manifest, + deployment *buildRofl.Deployment, + bnd *bundle.Bundle, +) { fmt.Println("Building an SGX-based Rust ROFL application...") detectBuildMode(npa) - features := sgxSetupBuildEnv(manifest, npa) + features := sgxSetupBuildEnv(deployment, npa) // First build for the default target. fmt.Println("Building ELF binary...") @@ -209,8 +214,8 @@ NextSetOfPrimes: } // sgxSetupBuildEnv sets up the SGX build environment and returns the list of features to enable. -func sgxSetupBuildEnv(manifest *buildRofl.Manifest, npa *common.NPASelection) []string { - setupBuildEnv(manifest, npa) +func sgxSetupBuildEnv(deployment *buildRofl.Deployment, npa *common.NPASelection) []string { + setupBuildEnv(deployment, npa) switch buildMode { case buildModeProduction, buildModeAuto: diff --git a/cmd/rofl/build/tdx.go b/cmd/rofl/build/tdx.go index 88b0903..22f3726 100644 --- a/cmd/rofl/build/tdx.go +++ b/cmd/rofl/build/tdx.go @@ -34,7 +34,13 @@ var ( ) // tdxBuildRaw builds a TDX-based "raw" ROFL app. -func tdxBuildRaw(tmpDir string, npa *common.NPASelection, manifest *buildRofl.Manifest, bnd *bundle.Bundle) error { +func tdxBuildRaw( + tmpDir string, + npa *common.NPASelection, + manifest *buildRofl.Manifest, + deployment *buildRofl.Deployment, + bnd *bundle.Bundle, +) error { wantedArtifacts := tdxGetDefaultArtifacts() tdxOverrideArtifacts(manifest, wantedArtifacts) artifacts := tdxFetchArtifacts(wantedArtifacts) @@ -42,7 +48,7 @@ func tdxBuildRaw(tmpDir string, npa *common.NPASelection, manifest *buildRofl.Ma fmt.Println("Building a TDX-based Rust ROFL application...") detectBuildMode(npa) - tdxSetupBuildEnv(manifest, npa) + tdxSetupBuildEnv(deployment, npa) // Obtain package metadata. pkgMeta, err := cargo.GetMetadata() @@ -246,7 +252,10 @@ func tdxBundleComponent( return err } - // TODO: For persistent disk, configure Stage2Persist flag and storage mode. + if tmpStorageKind == buildRofl.StorageKindDiskPersistent { + // TODO: For persistent disk, configure Stage2Persist flag and storage mode. + return fmt.Errorf("persistent disk not yet supported, use 'disk-ephemeral'") + } comp.TDX.ExtraKernelOptions = append(comp.TDX.ExtraKernelOptions, "oasis.stage2.storage_mode=disk", @@ -282,8 +291,8 @@ func tdxBundleComponent( } // tdxSetupBuildEnv sets up the TDX build environment. -func tdxSetupBuildEnv(manifest *buildRofl.Manifest, npa *common.NPASelection) { - setupBuildEnv(manifest, npa) +func tdxSetupBuildEnv(deployment *buildRofl.Deployment, npa *common.NPASelection) { + setupBuildEnv(deployment, npa) switch buildMode { case buildModeProduction, buildModeAuto: diff --git a/cmd/rofl/common/manifest.go b/cmd/rofl/common/manifest.go index 9ae2323..d6bb912 100644 --- a/cmd/rofl/common/manifest.go +++ b/cmd/rofl/common/manifest.go @@ -14,55 +14,60 @@ import ( // selection. // // In case there is an error in loading the manifest, it aborts the application. -func LoadManifestAndSetNPA(cfg *config.Config, npa *common.NPASelection) *rofl.Manifest { - manifest, err := MaybeLoadManifestAndSetNPA(cfg, npa) +func LoadManifestAndSetNPA(cfg *config.Config, npa *common.NPASelection, deployment string) (*rofl.Manifest, *rofl.Deployment) { + manifest, d, err := MaybeLoadManifestAndSetNPA(cfg, npa, deployment) cobra.CheckErr(err) - return manifest + return manifest, d } // MaybeLoadManifestAndSetNPA loads the ROFL app manifest and reconfigures the // network/paratime/account selection. // // In case there is an error in loading the manifest, it is returned. -func MaybeLoadManifestAndSetNPA(cfg *config.Config, npa *common.NPASelection) (*rofl.Manifest, error) { +func MaybeLoadManifestAndSetNPA(cfg *config.Config, npa *common.NPASelection, deployment string) (*rofl.Manifest, *rofl.Deployment, error) { manifest, err := rofl.LoadManifest() if err != nil { - return nil, err + return nil, nil, err } - switch manifest.Network { + d, ok := manifest.Deployments[deployment] + if !ok { + return nil, nil, fmt.Errorf("deployment '%s' does not exist", deployment) + } + + switch d.Network { case "": if npa.Network == nil { - return nil, fmt.Errorf("no network selected") + return nil, nil, fmt.Errorf("no network selected") } default: - npa.Network = cfg.Networks.All[manifest.Network] + npa.Network = cfg.Networks.All[d.Network] if npa.Network == nil { - return nil, fmt.Errorf("network '%s' does not exist", manifest.Network) + return nil, nil, fmt.Errorf("network '%s' does not exist", d.Network) } - npa.NetworkName = manifest.Network + npa.NetworkName = d.Network } - switch manifest.ParaTime { + switch d.ParaTime { case "": if npa.ParaTime == nil { - return nil, fmt.Errorf("no ParaTime selected") + return nil, nil, fmt.Errorf("no ParaTime selected") } default: - npa.ParaTime = npa.Network.ParaTimes.All[manifest.ParaTime] + npa.ParaTime = npa.Network.ParaTimes.All[d.ParaTime] if npa.ParaTime == nil { - return nil, fmt.Errorf("paratime '%s' does not exist", manifest.ParaTime) + return nil, nil, fmt.Errorf("paratime '%s' does not exist", d.ParaTime) } - npa.ParaTimeName = manifest.ParaTime + npa.ParaTimeName = d.ParaTime } - switch manifest.Admin { + switch d.Admin { case "": default: - accCfg, err := common.LoadAccountConfig(cfg, manifest.Admin) + accCfg, err := common.LoadAccountConfig(cfg, d.Admin) if err != nil { - return nil, err + return nil, nil, err } npa.Account = accCfg - npa.AccountName = manifest.Admin + npa.AccountName = d.Admin } - return manifest, nil + return manifest, d, nil } diff --git a/cmd/rofl/mgmt.go b/cmd/rofl/mgmt.go index 25b975b..1363b4c 100644 --- a/cmd/rofl/mgmt.go +++ b/cmd/rofl/mgmt.go @@ -33,8 +33,9 @@ var ( scheme string adminAddress string - appTEE string - appKind string + appTEE string + appKind string + deploymentName string initCmd = &cobra.Command{ Use: "init [--tee TEE] [--kind KIND]", @@ -71,15 +72,11 @@ var ( cobra.CheckErr(err) // Generate manifest and a default policy which does not accept any enclaves. - manifest := buildRofl.Manifest{ + deployment := &buildRofl.Deployment{ AppID: rofl.NewAppIDGlobalName("").String(), // Temporary for initial validation. - Name: appName, - Version: "0.1.0", Network: npa.NetworkName, ParaTime: npa.ParaTimeName, Admin: npa.AccountName, - TEE: appTEE, - Kind: appKind, Policy: &rofl.AppAuthPolicy{ Quotes: quote.Policy{ PCS: &pcs.QuotePolicy{ @@ -97,6 +94,12 @@ var ( TrustRoot: &buildRofl.TrustRootConfig{ Height: uint64(height), }, + } + manifest := buildRofl.Manifest{ + Name: appName, + Version: "0.1.0", + TEE: appTEE, + Kind: appKind, Resources: buildRofl.ResourcesConfig{ Memory: 512, CPUCount: 1, @@ -105,15 +108,22 @@ var ( Size: 512, }, }, + Deployments: map[string]*buildRofl.Deployment{ + buildRofl.DefaultDeploymentName: deployment, + }, } err = manifest.Validate() cobra.CheckErr(err) fmt.Printf("Creating a new ROFL app with default policy...\n") - fmt.Printf("Name: %s\n", manifest.Name) - fmt.Printf("Version: %s\n", manifest.Version) - fmt.Printf("TEE: %s\n", manifest.TEE) - fmt.Printf("Kind: %s\n", manifest.Kind) + fmt.Printf("Name: %s\n", manifest.Name) + fmt.Printf("Version: %s\n", manifest.Version) + fmt.Printf("TEE: %s\n", manifest.TEE) + fmt.Printf("Kind: %s\n", manifest.Kind) + fmt.Printf("Deployment '%s':\n", buildRofl.DefaultDeploymentName) + fmt.Printf(" Network: %s\n", deployment.Network) + fmt.Printf(" ParaTime: %s\n", deployment.ParaTime) + fmt.Printf(" Admin: %s\n", deployment.Admin) idScheme, ok := identifierSchemes[scheme] if !ok { @@ -122,7 +132,7 @@ var ( // Register a new ROFL application to determine the identifier. tx := rofl.NewCreateTx(nil, &rofl.Create{ - Policy: *manifest.Policy, + Policy: *deployment.Policy, Scheme: idScheme, }) @@ -132,7 +142,7 @@ var ( var appID rofl.AppID common.BroadcastTransaction(ctx, npa.ParaTime, conn, sigTx, meta, &appID) - manifest.AppID = appID.String() + deployment.AppID = appID.String() fmt.Printf("Created ROFL application: %s\n", appID) @@ -157,8 +167,8 @@ var ( if len(args) > 0 { policy = loadPolicy(args[0]) } else { - manifest := roflCommon.LoadManifestAndSetNPA(cfg, npa) - policy = manifest.Policy + _, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName) + policy = deployment.Policy } if npa.Account == nil { @@ -218,13 +228,13 @@ var ( rawAppID = args[0] policy = loadPolicy(policyFn) } else { - manifest := roflCommon.LoadManifestAndSetNPA(cfg, npa) - rawAppID = manifest.AppID + _, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName) + rawAppID = deployment.AppID - if adminAddress == "" && manifest.Admin != "" { + if adminAddress == "" && deployment.Admin != "" { adminAddress = "self" } - policy = manifest.Policy + policy = deployment.Policy } var appID rofl.AppID if err := appID.UnmarshalText([]byte(rawAppID)); err != nil { @@ -295,8 +305,8 @@ var ( if len(args) > 0 { rawAppID = args[0] } else { - manifest := roflCommon.LoadManifestAndSetNPA(cfg, npa) - rawAppID = manifest.AppID + _, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName) + rawAppID = deployment.AppID } var appID rofl.AppID if err := appID.UnmarshalText([]byte(rawAppID)); err != nil { @@ -344,8 +354,8 @@ var ( if len(args) > 0 { rawAppID = args[0] } else { - manifest := roflCommon.LoadManifestAndSetNPA(cfg, npa) - rawAppID = manifest.AppID + _, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName) + rawAppID = deployment.AppID } var appID rofl.AppID if err := appID.UnmarshalText([]byte(rawAppID)); err != nil { @@ -406,26 +416,35 @@ func loadPolicy(fn string) *rofl.AppAuthPolicy { } func init() { + deploymentFlags := flag.NewFlagSet("", flag.ContinueOnError) + deploymentFlags.StringVar(&deploymentName, "deployment", buildRofl.DefaultDeploymentName, "deployment name") + updateFlags := flag.NewFlagSet("", flag.ContinueOnError) updateFlags.StringVar(&policyFn, "policy", "", "set the ROFL application policy") updateFlags.StringVar(&adminAddress, "admin", "", "set the administrator address") + updateCmd.Flags().AddFlagSet(deploymentFlags) initCmd.Flags().AddFlagSet(common.SelectorFlags) initCmd.Flags().AddFlagSet(common.RuntimeTxFlags) + initCmd.Flags().AddFlagSet(deploymentFlags) initCmd.Flags().StringVar(&appTEE, "tee", "tdx", "TEE kind [tdx, sgx]") initCmd.Flags().StringVar(&appKind, "kind", "container", "ROFL app kind [container, raw]") initCmd.Flags().StringVar(&scheme, "scheme", "cn", "app ID generation scheme: creator+round+index [cri] or creator+nonce [cn]") createCmd.Flags().AddFlagSet(common.SelectorFlags) createCmd.Flags().AddFlagSet(common.RuntimeTxFlags) + createCmd.Flags().AddFlagSet(deploymentFlags) createCmd.Flags().StringVar(&scheme, "scheme", "cn", "app ID generation scheme: creator+round+index [cri] or creator+nonce [cn]") updateCmd.Flags().AddFlagSet(common.SelectorFlags) updateCmd.Flags().AddFlagSet(common.RuntimeTxFlags) + updateCmd.Flags().AddFlagSet(deploymentFlags) updateCmd.Flags().AddFlagSet(updateFlags) removeCmd.Flags().AddFlagSet(common.SelectorFlags) removeCmd.Flags().AddFlagSet(common.RuntimeTxFlags) + removeCmd.Flags().AddFlagSet(deploymentFlags) showCmd.Flags().AddFlagSet(common.SelectorFlags) + showCmd.Flags().AddFlagSet(deploymentFlags) }