Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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: 1 addition & 1 deletion .github/workflows/validation-sfcompute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
TEST_PUBLIC_KEY_BASE64: ${{ secrets.TEST_PUBLIC_KEY_BASE64 }}
VALIDATION_TEST: true
run: |
cd v1/providers/sfcompute
cd v1/providers/sfcomputev2
go test -v -short=false -timeout=30m ./...

- name: Upload test results
Expand Down
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.50.0
golang.org/x/text v0.36.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" //nolint:gosec // not a secret
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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

manually tested that this image works for us? Docker, UFW, etc?

)
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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok if this collides with the existing cloudcred?


// 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
Loading