Skip to content
Open
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
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/nebius/gosdk v0.0.0-20250826102719-940ad1dfb5de
github.com/pkg/errors v0.9.1
github.com/sfcompute/nodes-go v0.1.0-alpha.4
github.com/sfcompute/sfc-go v0.1.0-preview
github.com/stretchr/testify v1.11.1
golang.org/x/crypto v0.47.0
golang.org/x/text v0.33.0
Expand Down Expand Up @@ -85,6 +86,7 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spyzhov/ajson v0.8.0 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,16 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sfcompute/nodes-go v0.1.0-alpha.4 h1:oFBWcMPSpqLYm/NDs5I1jTvzgx9rsXDL9Ghsm30Hc0Q=
github.com/sfcompute/nodes-go v0.1.0-alpha.4/go.mod h1:nUviHgK+Fgt2hDFcRL3M8VoyiypC8fc0dsY8C30QU8M=
github.com/sfcompute/sfc-go v0.1.0-preview h1:yJ6ICglA/JZal2kauzb2aZlV9XdLPejsvFpsKwwThkQ=
github.com/sfcompute/sfc-go v0.1.0-preview/go.mod h1:vhUpRpAHKitZzzWPg87RjreC+pzK57PGe4ZuSIQSk94=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spyzhov/ajson v0.8.0 h1:sFXyMbi4Y/BKjrsfkUZHSjA2JM1184enheSjjoT/zCc=
github.com/spyzhov/ajson v0.8.0/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
23 changes: 23 additions & 0 deletions v1/providers/sfcomputev2/brev_constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package v2

// Package-internal constants — SSH defaults and internal tag keys.
const (
defaultPort = 22
defaultSSHUsername = "ubuntu"

// Internal tag keys written to every SFCompute V2 instance. These are stripped from
// v1.Instance.Tags on read so they don't surface as user-facing tags.
tagKeyCloudCredRefID = "brev-cloud-cred-ref-id"
tagKeyRefID = "brev-ref-id"
)

// Brev environment config for SFCompute V2.
// TODO: source these from environment variables rather than hardcoding them here.
const (
// BrevProductionCapacityID is the SFCompute V2 capacity ID for Brev production instances.
BrevProductionCapacityID = "brev-production-capacity"

// BrevProductionImageID is the SFCompute image for Brev production instances
// (ubuntu-24.04.4-cuda-12.8, vm_images.vm_image_id).
BrevProductionImageID = "vmi_4GwEvmclFURy7ztFQjOdr"
)
24 changes: 24 additions & 0 deletions v1/providers/sfcomputev2/capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package v2

import (
"context"

v1 "github.com/brevdev/cloud/v1"
)

func getSFCCapabilitiesV2() v1.Capabilities {
return v1.Capabilities{
v1.CapabilityCreateInstance,
v1.CapabilityTerminateInstance,
v1.CapabilityCreateTerminateInstance,
v1.CapabilityTags,
}
}

func (c *SFCClientV2) GetCapabilities(_ context.Context) (v1.Capabilities, error) {
return getSFCCapabilitiesV2(), nil
}

func (c *SFCCredentialV2) GetCapabilities(_ context.Context) (v1.Capabilities, error) {
return getSFCCapabilitiesV2(), nil
}
99 changes: 99 additions & 0 deletions v1/providers/sfcomputev2/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package v2

import (
"context"

v1 "github.com/brevdev/cloud/v1"
sfc "github.com/sfcompute/sfc-go"
)

const CloudProviderID = "sfcompute"

// SFCCredentialV2 holds authentication details for a Brev-managed SFCompute V2 account.
type SFCCredentialV2 struct {
RefID string
APIKey string `json:"api_key"`
}

var _ v1.CloudCredential = &SFCCredentialV2{}

func NewSFCCredentialV2(refID, apiKey string) *SFCCredentialV2 {
return &SFCCredentialV2{
RefID: refID,
APIKey: apiKey,
}
}

func (c *SFCCredentialV2) GetReferenceID() string {
return c.RefID
}

func (c *SFCCredentialV2) GetAPIType() v1.APIType {
return v1.APITypeGlobal
}

func (c *SFCCredentialV2) GetCloudProviderID() v1.CloudProviderID {
return CloudProviderID
}

func (c *SFCCredentialV2) GetTenantID() (string, error) {
return "", nil
}

type SFCClientV2 struct {
v1.NotImplCloudClient
refID string
location string
client *sfc.SDK
logger v1.Logger
}

var _ v1.CloudClient = &SFCClientV2{}

type SFCClientV2Option func(c *SFCClientV2)

func WithLogger(logger v1.Logger) SFCClientV2Option {
return func(c *SFCClientV2) {
c.logger = logger
}
}

func (c *SFCCredentialV2) MakeClientWithOptions(_ context.Context, location string, opts ...SFCClientV2Option) (v1.CloudClient, error) {
sfcClient := &SFCClientV2{
refID: c.RefID,
location: location,
client: sfc.New(sfc.WithSecurity(c.APIKey)),
logger: &v1.NoopLogger{},
}

for _, opt := range opts {
opt(sfcClient)
}

return sfcClient, nil
}

func (c *SFCCredentialV2) MakeClient(ctx context.Context, location string) (v1.CloudClient, error) {
return c.MakeClientWithOptions(ctx, location)
}

func (c *SFCClientV2) GetAPIType() v1.APIType {
return v1.APITypeGlobal
}

func (c *SFCClientV2) GetCloudProviderID() v1.CloudProviderID {
return CloudProviderID
}

func (c *SFCClientV2) GetReferenceID() string {
return c.refID
}

func (c *SFCClientV2) GetTenantID() (string, error) {
return "", nil
}

func (c *SFCClientV2) MakeClient(_ context.Context, location string) (v1.CloudClient, error) {
c.location = location
return c, nil
}
Loading