Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions cmd/weaver/commands/block/node/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashgraph/solo-weaver/cmd/weaver/commands/common"
"github.com/hashgraph/solo-weaver/internal/config"
"github.com/hashgraph/solo-weaver/internal/workflows"
"github.com/hashgraph/solo-weaver/pkg/hardware"
"github.com/joomcode/errorx"
"github.com/spf13/cobra"
)
Expand All @@ -25,6 +26,12 @@ var checkCmd = &cobra.Command{
return errorx.IllegalArgument.New("profile flag is required")
}

// Validate profile early for better error messages
if !hardware.IsValidProfile(flagProfile) {
return errorx.IllegalArgument.New("unsupported profile: %q. Supported profiles: %v",
flagProfile, hardware.SupportedProfiles())
}

// Set the profile in the global config so other components can access it
config.SetProfile(flagProfile)

Expand Down
7 changes: 7 additions & 0 deletions cmd/weaver/commands/block/node/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashgraph/solo-weaver/cmd/weaver/commands/common"
"github.com/hashgraph/solo-weaver/internal/config"
"github.com/hashgraph/solo-weaver/internal/workflows"
"github.com/hashgraph/solo-weaver/pkg/hardware"
"github.com/hashgraph/solo-weaver/pkg/sanity"
"github.com/joomcode/errorx"
"github.com/spf13/cobra"
Expand All @@ -27,6 +28,12 @@ var installCmd = &cobra.Command{
return errorx.IllegalArgument.New("profile flag is required")
}

// Validate profile early for better error messages
if !hardware.IsValidProfile(flagProfile) {
return errorx.IllegalArgument.New("unsupported profile: %q. Supported profiles: %v",
flagProfile, hardware.SupportedProfiles())
}

// Set the profile in the global config so other components can access it
config.SetProfile(flagProfile)

Expand Down
8 changes: 7 additions & 1 deletion cmd/weaver/commands/block/node/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashgraph/solo-weaver/cmd/weaver/commands/common"
"github.com/hashgraph/solo-weaver/internal/config"
"github.com/hashgraph/solo-weaver/internal/workflows"
"github.com/hashgraph/solo-weaver/pkg/hardware"
"github.com/joomcode/errorx"
"github.com/spf13/cobra"
)
Expand All @@ -30,8 +31,13 @@ WARNING: This operation is destructive and cannot be undone. All block data will
return errorx.IllegalArgument.Wrap(err, "failed to get profile flag")
}

// Set the profile in the global config if provided
// Validate profile early if provided
if flagProfile != "" {
if !hardware.IsValidProfile(flagProfile) {
return errorx.IllegalArgument.New("unsupported profile: %q. Supported profiles: %v",
flagProfile, hardware.SupportedProfiles())
}
// Set the profile in the global config
config.SetProfile(flagProfile)
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/weaver/commands/kube/cluster/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashgraph/solo-weaver/cmd/weaver/commands/common"
"github.com/hashgraph/solo-weaver/internal/config"
"github.com/hashgraph/solo-weaver/internal/workflows"
"github.com/hashgraph/solo-weaver/pkg/hardware"
"github.com/joomcode/errorx"
"github.com/spf13/cobra"
)
Expand All @@ -25,6 +26,17 @@ var installCmd = &cobra.Command{
return errorx.IllegalArgument.New("profile flag is required")
}

// Validate node type and profile early for better error messages
if !hardware.IsValidNodeType(flagNodeType) {
return errorx.IllegalArgument.New("unsupported node type: %q. Supported types: %v",
flagNodeType, hardware.SupportedNodeTypes())
}

if !hardware.IsValidProfile(flagProfile) {
return errorx.IllegalArgument.New("unsupported profile: %q. Supported profiles: %v",
flagProfile, hardware.SupportedProfiles())
}

// Set the profile in the global config so other components can access it
config.SetProfile(flagProfile)

Expand Down
3 changes: 2 additions & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@ Most installation commands support these execution control flags:

## Deployment Profiles

Solo Provisioner supports four deployment profiles that configure behavior and defaults:
Solo Provisioner supports five deployment profiles that configure behavior and defaults:

| Profile | Description | Use Case |
|---------|-------------|----------|
| `local` | Local development and testing | Development, CI/CD |
| `perfnet` | Performance testing network | Load testing |
| `testnet` | Hedera Testnet | Integration testing |
| `previewnet` | Hedera Previewnet | Preview/staging testing |
| `mainnet` | Hedera Mainnet | Production deployment |

> **Important**: Always use `--profile` to specify your target environment.
Expand Down
10 changes: 6 additions & 4 deletions internal/core/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ const (
NodeTypeRelay = "relay"

// Deployment profiles
ProfileLocal = "local"
ProfilePerfnet = "perfnet"
ProfileTestnet = "testnet"
ProfileMainnet = "mainnet"
ProfileLocal = "local"
ProfilePerfnet = "perfnet"
ProfileTestnet = "testnet"
ProfilePreviewnet = "previewnet"
ProfileMainnet = "mainnet"
)

var allProfiles = []string{
ProfileLocal,
ProfilePerfnet,
ProfileTestnet,
ProfilePreviewnet,
ProfileMainnet,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/workflows/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func CheckHostProfileStep(nodeType string, profile string) automa.Builder {
if !hardware.IsValidNodeType(nodeType) {
return automa.FailureReport(stp,
automa.WithError(
errorx.IllegalArgument.New("unsupported node type: %s. Supported types: %v",
errorx.IllegalArgument.New("unsupported node type: %q. Supported types: %v",
nodeType, hardware.SupportedNodeTypes())))
}

Expand Down
40 changes: 38 additions & 2 deletions pkg/hardware/base_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package hardware

import (
"fmt"
"strings"
)

const (
Expand Down Expand Up @@ -71,11 +72,46 @@ func (b *baseNode) ValidateMemory() error {
return nil
}

// ValidateStorage validates storage requirements using common logic
// ValidateStorage validates storage requirements using common logic.
// If MinSSDStorageGB or MinHDDStorageGB are set, validates those separately.
// Otherwise, validates total storage against MinStorageGB.
func (b *baseNode) ValidateStorage() error {
// Check if we need to validate SSD/HDD separately
if b.minimalRequirements.MinSSDStorageGB > 0 || b.minimalRequirements.MinHDDStorageGB > 0 {
return b.validateSplitStorage()
}

// Default: validate total storage
totalStorageGB := b.actualHostProfile.GetTotalStorageGB()
if int(totalStorageGB) < b.minimalRequirements.MinStorageGB {
return fmt.Errorf("storage does not meet %s requirements (minimum %d GB)", b.nodeType, b.minimalRequirements.MinStorageGB)
return fmt.Errorf("storage does not meet %s requirements (minimum %d GB, found %d GB)",
b.nodeType, b.minimalRequirements.MinStorageGB, totalStorageGB)
}
return nil
}

// validateSplitStorage validates SSD and HDD storage separately
func (b *baseNode) validateSplitStorage() error {
var errs []string

if b.minimalRequirements.MinSSDStorageGB > 0 {
ssdStorageGB := b.actualHostProfile.GetSSDStorageGB()
if int(ssdStorageGB) < b.minimalRequirements.MinSSDStorageGB {
errs = append(errs, fmt.Sprintf("SSD/NVMe storage: minimum %d GB required, found %d GB",
b.minimalRequirements.MinSSDStorageGB, ssdStorageGB))
}
}

if b.minimalRequirements.MinHDDStorageGB > 0 {
hddStorageGB := b.actualHostProfile.GetHDDStorageGB()
if int(hddStorageGB) < b.minimalRequirements.MinHDDStorageGB {
errs = append(errs, fmt.Sprintf("HDD storage: minimum %d GB required, found %d GB",
b.minimalRequirements.MinHDDStorageGB, hddStorageGB))
}
}

if len(errs) > 0 {
return fmt.Errorf("storage does not meet %s requirements: %s", b.nodeType, strings.Join(errs, "; "))
}
return nil
}
Expand Down
27 changes: 0 additions & 27 deletions pkg/hardware/block_node.go

This file was deleted.

27 changes: 0 additions & 27 deletions pkg/hardware/consensus_node.go

This file was deleted.

38 changes: 20 additions & 18 deletions pkg/hardware/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func SupportedNodeTypes() []string {

// SupportedProfiles returns all supported deployment profiles
func SupportedProfiles() []string {
return []string{core.ProfileLocal, core.ProfilePerfnet, core.ProfileTestnet, core.ProfileMainnet}
return []string{core.ProfileLocal, core.ProfilePerfnet, core.ProfileTestnet, core.ProfilePreviewnet, core.ProfileMainnet}
}

// IsValidNodeType checks if the given node type is supported
Expand All @@ -41,27 +41,29 @@ func IsValidProfile(profile string) bool {
return false
}

// CreateNodeSpec creates the appropriate node spec based on node type, profile and host profile
// CreateNodeSpec creates the appropriate node spec based on node type, profile and host profile.
// This function uses a requirements registry that maps (nodeType, profile) combinations
// to their specific hardware requirements, properly separating the concerns of
// node type (what kind of node) and profile (deployment environment).
func CreateNodeSpec(nodeType string, profile string, hostProfile HostProfile) (Spec, error) {
normalized := strings.ToLower(nodeType)
normalizedNodeType := strings.ToLower(nodeType)
normalizedProfile := strings.ToLower(profile)

// For local profile, use local node specs regardless of node type
if normalizedProfile == core.ProfileLocal {
return NewLocalNodeSpec(hostProfile), nil
// Validate node type
if !IsValidNodeType(normalizedNodeType) {
return nil, errorx.IllegalArgument.New("unsupported node type: %q. Supported types: %v", nodeType, SupportedNodeTypes())
}

// For other profiles, use node-specific requirements
switch normalized {
case core.NodeTypeBlock:
return NewBlockNodeSpec(hostProfile), nil
case core.NodeTypeConsensus:
return NewConsensusNodeSpec(hostProfile), nil
default:
supportedTypes := make([]string, len(SupportedNodeTypes()))
for i, t := range SupportedNodeTypes() {
supportedTypes[i] = string(t)
}
return nil, errorx.IllegalArgument.New("unsupported node type: %s. Supported types: %v", nodeType, supportedTypes)
// Validate profile
if !IsValidProfile(normalizedProfile) {
return nil, errorx.IllegalArgument.New("unsupported profile: %q. Supported profiles: %v", profile, SupportedProfiles())
}

// Use the new unified node spec that looks up requirements from the registry
spec, err := NewNodeSpec(normalizedNodeType, normalizedProfile, hostProfile)
if err != nil {
return nil, errorx.IllegalArgument.Wrap(err, "failed to create node spec")
}

return spec, nil
}
Loading