Skip to content

Commit dc53ca5

Browse files
authored
Merge pull request #390 from DefangLabs/lio-refactor-client
separate fabric from playground client
2 parents 498fa2c + 1e5ec5c commit dc53ca5

File tree

8 files changed

+166
-146
lines changed

8 files changed

+166
-146
lines changed

src/cmd/cli/command/track.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ func Track(name string, props ...P) {
2323
if disableAnalytics {
2424
return
2525
}
26+
var client cliClient.FabricClient = client
2627
if client == nil {
2728
client, _ = cli.Connect(cluster, nil)
2829
}
2930
trackWG.Add(1)
30-
go func(client cliClient.Client) {
31+
go func(client cliClient.FabricClient) {
3132
defer trackWG.Done()
3233
_ = client.Track(name, props...)
3334
}(client)

src/pkg/cli/client/client.go

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,40 @@ type ProjectLoader interface {
2020
LoadWithProjectName(string) (*compose.Project, error)
2121
}
2222

23-
type Client interface {
24-
// Promote(google.protobuf.Empty) returns (google.protobuf.Empty);
25-
// Subscribe(context.Context, *v1.SubscribeRequest) (*v1.SubscribeResponse, error)
26-
// Update(context.Context, *v1.Service) (*v1.ServiceInfo, error)
23+
type FabricClient interface {
2724
AgreeToS(context.Context) error
25+
CheckLoginAndToS(context.Context) error
26+
DelegateSubdomainZone(context.Context, *defangv1.DelegateSubdomainZoneRequest) (*defangv1.DelegateSubdomainZoneResponse, error)
27+
DeleteSubdomainZone(context.Context) error
28+
GenerateFiles(context.Context, *defangv1.GenerateFilesRequest) (*defangv1.GenerateFilesResponse, error)
29+
GetDelegateSubdomainZone(context.Context) (*defangv1.DelegateSubdomainZoneResponse, error)
30+
GetVersions(context.Context) (*defangv1.Version, error)
31+
Publish(context.Context, *defangv1.PublishRequest) error
32+
RevokeToken(context.Context) error
33+
// Subscribe(context.Context, *v1.SubscribeRequest) (*v1.SubscribeResponse, error)
34+
Token(context.Context, *defangv1.TokenRequest) (*defangv1.TokenResponse, error)
35+
Track(string, ...Property) error
36+
}
37+
38+
type Client interface {
39+
FabricClient
40+
2841
BootstrapCommand(context.Context, string) (types.ETag, error)
2942
BootstrapList(context.Context) ([]string, error)
30-
CheckLoginAndToS(context.Context) error
3143
CreateUploadURL(context.Context, *defangv1.UploadURLRequest) (*defangv1.UploadURLResponse, error)
32-
DelegateSubdomainZone(context.Context, *defangv1.DelegateSubdomainZoneRequest) (*defangv1.DelegateSubdomainZoneResponse, error)
3344
// Deprecated: Use Deploy or Destroy instead.
3445
Delete(context.Context, *defangv1.DeleteRequest) (*defangv1.DeleteResponse, error)
3546
DeleteConfig(context.Context, *defangv1.Secrets) error
36-
DeleteSubdomainZone(context.Context) error
3747
Deploy(context.Context, *defangv1.DeployRequest) (*defangv1.DeployResponse, error)
3848
Destroy(context.Context) (types.ETag, error)
39-
GenerateFiles(context.Context, *defangv1.GenerateFilesRequest) (*defangv1.GenerateFilesResponse, error)
40-
GetDelegateSubdomainZone(context.Context) (*defangv1.DelegateSubdomainZoneResponse, error)
4149
GetService(context.Context, *defangv1.ServiceID) (*defangv1.ServiceInfo, error)
4250
GetServices(context.Context) (*defangv1.ListServicesResponse, error)
43-
GetVersions(context.Context) (*defangv1.Version, error)
4451
ListConfig(context.Context) (*defangv1.Secrets, error)
45-
Publish(context.Context, *defangv1.PublishRequest) error
4652
PutConfig(context.Context, *defangv1.SecretValue) error
4753
Restart(context.Context, ...string) (types.ETag, error)
48-
RevokeToken(context.Context) error
4954
ServiceDNS(name string) string
5055
Tail(context.Context, *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error)
5156
TearDown(context.Context) error
52-
Token(context.Context, *defangv1.TokenRequest) (*defangv1.TokenResponse, error)
53-
Track(string, ...Property) error
5457
WhoAmI(context.Context) (*defangv1.WhoAmIResponse, error)
5558

5659
LoadProject() (*compose.Project, error)

src/pkg/cli/client/grpc.go

Lines changed: 2 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package client
33
import (
44
"context"
55
"encoding/json"
6-
"errors"
76
"fmt"
87
"net/http"
98
"os"
@@ -13,12 +12,10 @@ import (
1312
"time"
1413

1514
"github.com/DefangLabs/defang/src/pkg/auth"
16-
"github.com/DefangLabs/defang/src/pkg/term"
1715
"github.com/DefangLabs/defang/src/pkg/types"
1816
defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1"
1917
"github.com/DefangLabs/defang/src/protos/io/defang/v1/defangv1connect"
2018
"github.com/bufbuild/connect-go"
21-
compose "github.com/compose-spec/compose-go/v2/types"
2219
"github.com/google/uuid"
2320
"google.golang.org/protobuf/types/known/emptypb"
2421
)
@@ -31,6 +28,8 @@ type GrpcClient struct {
3128
Loader ProjectLoader
3229
}
3330

31+
var _ FabricClient = &GrpcClient{}
32+
3433
func NewGrpcClient(host, accessToken string, tenantID types.TenantID, loader ProjectLoader) *GrpcClient {
3534
baseUrl := "http://"
3635
if strings.HasSuffix(host, ":443") {
@@ -63,11 +62,6 @@ func getMsg[T any](resp *connect.Response[T], err error) (*T, error) {
6362
return resp.Msg, nil
6463
}
6564

66-
func (g GrpcClient) LoadProject() (*compose.Project, error) {
67-
projectName, _ := g.LoadProjectName()
68-
return g.Loader.LoadWithDefaultProjectName(projectName)
69-
}
70-
7165
func (g GrpcClient) GetVersions(ctx context.Context) (*defangv1.Version, error) {
7266
return getMsg(g.client.GetVersion(ctx, &connect.Request[emptypb.Empty]{}))
7367
}
@@ -82,59 +76,15 @@ func (g GrpcClient) RevokeToken(ctx context.Context) error {
8276
return err
8377
}
8478

85-
func (g GrpcClient) Update(ctx context.Context, req *defangv1.Service) (*defangv1.ServiceInfo, error) {
86-
return getMsg(g.client.Update(ctx, connect.NewRequest(req)))
87-
}
88-
89-
func (g GrpcClient) Deploy(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
90-
// TODO: remove this when playground supports BYOD
91-
for _, service := range req.Services {
92-
if service.Domainname != "" {
93-
term.Warnf("Defang provider does not support the domainname field for now, service: %v, domain: %v", service.Name, service.Domainname)
94-
}
95-
}
96-
return getMsg(g.client.Deploy(ctx, connect.NewRequest(req)))
97-
}
98-
99-
func (g GrpcClient) GetService(ctx context.Context, req *defangv1.ServiceID) (*defangv1.ServiceInfo, error) {
100-
return getMsg(g.client.Get(ctx, connect.NewRequest(req)))
101-
}
102-
103-
func (g GrpcClient) Delete(ctx context.Context, req *defangv1.DeleteRequest) (*defangv1.DeleteResponse, error) {
104-
return getMsg(g.client.Delete(ctx, connect.NewRequest(req)))
105-
}
106-
10779
func (g GrpcClient) Publish(ctx context.Context, req *defangv1.PublishRequest) error {
10880
_, err := g.client.Publish(ctx, connect.NewRequest(req))
10981
return err
11082
}
11183

112-
func (g GrpcClient) GetServices(ctx context.Context) (*defangv1.ListServicesResponse, error) {
113-
return getMsg(g.client.GetServices(ctx, &connect.Request[emptypb.Empty]{}))
114-
}
115-
11684
func (g GrpcClient) GenerateFiles(ctx context.Context, req *defangv1.GenerateFilesRequest) (*defangv1.GenerateFilesResponse, error) {
11785
return getMsg(g.client.GenerateFiles(ctx, connect.NewRequest(req)))
11886
}
11987

120-
func (g GrpcClient) PutConfig(ctx context.Context, req *defangv1.SecretValue) error {
121-
_, err := g.client.PutSecret(ctx, connect.NewRequest(req))
122-
return err
123-
}
124-
125-
func (g GrpcClient) DeleteConfig(ctx context.Context, req *defangv1.Secrets) error {
126-
_, err := g.client.DeleteSecrets(ctx, connect.NewRequest(&defangv1.Secrets{Names: req.Names}))
127-
return err
128-
}
129-
130-
func (g GrpcClient) ListConfig(ctx context.Context) (*defangv1.Secrets, error) {
131-
return getMsg(g.client.ListSecrets(ctx, &connect.Request[emptypb.Empty]{}))
132-
}
133-
134-
func (g GrpcClient) CreateUploadURL(ctx context.Context, req *defangv1.UploadURLRequest) (*defangv1.UploadURLResponse, error) {
135-
return getMsg(g.client.CreateUploadURL(ctx, connect.NewRequest(req)))
136-
}
137-
13888
func (g GrpcClient) WhoAmI(ctx context.Context) (*defangv1.WhoAmIResponse, error) {
13989
return getMsg(g.client.WhoAmI(ctx, &connect.Request[emptypb.Empty]{}))
14090
}
@@ -152,14 +102,6 @@ func (g GrpcClient) GetDelegateSubdomainZone(ctx context.Context) (*defangv1.Del
152102
return getMsg(g.client.GetDelegateSubdomainZone(ctx, &connect.Request[emptypb.Empty]{}))
153103
}
154104

155-
func (g *GrpcClient) Tail(ctx context.Context, req *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) {
156-
return g.client.Tail(ctx, connect.NewRequest(req))
157-
}
158-
159-
func (g *GrpcClient) BootstrapCommand(ctx context.Context, command string) (types.ETag, error) {
160-
return "", errors.New("the bootstrap command is not valid for the Defang provider")
161-
}
162-
163105
func (g *GrpcClient) AgreeToS(ctx context.Context) error {
164106
_, err := g.client.SignEULA(ctx, &connect.Request[emptypb.Empty]{})
165107
return err
@@ -190,58 +132,3 @@ func (g *GrpcClient) CheckLoginAndToS(ctx context.Context) error {
190132
_, err := g.client.CheckToS(ctx, &connect.Request[emptypb.Empty]{})
191133
return err
192134
}
193-
194-
func (g *GrpcClient) Destroy(ctx context.Context) (types.ETag, error) {
195-
// Get all the services in the project and delete them all at once
196-
project, err := g.GetServices(ctx)
197-
if err != nil {
198-
return "", err
199-
}
200-
if len(project.Services) == 0 {
201-
return "", errors.New("no services found")
202-
}
203-
var names []string
204-
for _, service := range project.Services {
205-
names = append(names, service.Service.Name)
206-
}
207-
resp, err := g.Delete(ctx, &defangv1.DeleteRequest{Names: names})
208-
if err != nil {
209-
return "", err
210-
}
211-
return resp.Etag, nil
212-
}
213-
214-
func (g *GrpcClient) TearDown(ctx context.Context) error {
215-
return errors.New("the teardown command is not valid for the Defang provider")
216-
}
217-
218-
func (g *GrpcClient) BootstrapList(context.Context) ([]string, error) {
219-
return nil, errors.New("this command is not valid for the Defang provider")
220-
}
221-
222-
func (g *GrpcClient) Restart(ctx context.Context, names ...string) (types.ETag, error) {
223-
// For now, we'll just get the service info and pass it back to Deploy as-is.
224-
services := make([]*defangv1.Service, 0, len(names))
225-
for _, name := range names {
226-
serviceInfo, err := g.GetService(ctx, &defangv1.ServiceID{Name: name})
227-
if err != nil {
228-
return "", err
229-
}
230-
services = append(services, serviceInfo.Service)
231-
}
232-
233-
dr, err := g.Deploy(ctx, &defangv1.DeployRequest{Services: services})
234-
if err != nil {
235-
return "", err
236-
}
237-
return dr.Etag, nil
238-
}
239-
240-
func (g GrpcClient) ServiceDNS(name string) string {
241-
whoami, _ := g.WhoAmI(context.TODO())
242-
return whoami.Tenant + "-" + name
243-
}
244-
245-
func (g GrpcClient) LoadProjectName() (string, error) {
246-
return string(g.tenantID), nil
247-
}

src/pkg/cli/client/playground.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"github.com/DefangLabs/defang/src/pkg/term"
8+
"github.com/DefangLabs/defang/src/pkg/types"
9+
defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1"
10+
"github.com/bufbuild/connect-go"
11+
compose "github.com/compose-spec/compose-go/v2/types"
12+
"google.golang.org/protobuf/types/known/emptypb"
13+
)
14+
15+
type PlaygroundClient struct {
16+
GrpcClient
17+
}
18+
19+
func (g PlaygroundClient) LoadProject() (*compose.Project, error) {
20+
projectName, _ := g.LoadProjectName()
21+
return g.Loader.LoadWithDefaultProjectName(projectName)
22+
}
23+
24+
func (g PlaygroundClient) Update(ctx context.Context, req *defangv1.Service) (*defangv1.ServiceInfo, error) {
25+
return getMsg(g.client.Update(ctx, connect.NewRequest(req)))
26+
}
27+
28+
func (g PlaygroundClient) Deploy(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
29+
// TODO: remove this when playground supports BYOD
30+
for _, service := range req.Services {
31+
if service.Domainname != "" {
32+
term.Warnf("Defang provider does not support the domainname field for now, service: %v, domain: %v", service.Name, service.Domainname)
33+
}
34+
}
35+
return getMsg(g.client.Deploy(ctx, connect.NewRequest(req)))
36+
}
37+
38+
func (g PlaygroundClient) GetService(ctx context.Context, req *defangv1.ServiceID) (*defangv1.ServiceInfo, error) {
39+
return getMsg(g.client.Get(ctx, connect.NewRequest(req)))
40+
}
41+
42+
func (g PlaygroundClient) Delete(ctx context.Context, req *defangv1.DeleteRequest) (*defangv1.DeleteResponse, error) {
43+
return getMsg(g.client.Delete(ctx, connect.NewRequest(req)))
44+
}
45+
46+
func (g PlaygroundClient) GetServices(ctx context.Context) (*defangv1.ListServicesResponse, error) {
47+
return getMsg(g.client.GetServices(ctx, &connect.Request[emptypb.Empty]{}))
48+
}
49+
50+
func (g PlaygroundClient) PutConfig(ctx context.Context, req *defangv1.SecretValue) error {
51+
_, err := g.client.PutSecret(ctx, connect.NewRequest(req))
52+
return err
53+
}
54+
55+
func (g PlaygroundClient) DeleteConfig(ctx context.Context, req *defangv1.Secrets) error {
56+
_, err := g.client.DeleteSecrets(ctx, connect.NewRequest(&defangv1.Secrets{Names: req.Names}))
57+
return err
58+
}
59+
60+
func (g PlaygroundClient) ListConfig(ctx context.Context) (*defangv1.Secrets, error) {
61+
return getMsg(g.client.ListSecrets(ctx, &connect.Request[emptypb.Empty]{}))
62+
}
63+
64+
func (g PlaygroundClient) CreateUploadURL(ctx context.Context, req *defangv1.UploadURLRequest) (*defangv1.UploadURLResponse, error) {
65+
return getMsg(g.client.CreateUploadURL(ctx, connect.NewRequest(req)))
66+
}
67+
68+
func (g *PlaygroundClient) Tail(ctx context.Context, req *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) {
69+
return g.client.Tail(ctx, connect.NewRequest(req))
70+
}
71+
72+
func (g *PlaygroundClient) BootstrapCommand(ctx context.Context, command string) (types.ETag, error) {
73+
return "", errors.New("the bootstrap command is not valid for the Defang provider")
74+
}
75+
func (g *PlaygroundClient) Destroy(ctx context.Context) (types.ETag, error) {
76+
// Get all the services in the project and delete them all at once
77+
project, err := g.GetServices(ctx)
78+
if err != nil {
79+
return "", err
80+
}
81+
if len(project.Services) == 0 {
82+
return "", errors.New("no services found")
83+
}
84+
var names []string
85+
for _, service := range project.Services {
86+
names = append(names, service.Service.Name)
87+
}
88+
resp, err := g.Delete(ctx, &defangv1.DeleteRequest{Names: names})
89+
if err != nil {
90+
return "", err
91+
}
92+
return resp.Etag, nil
93+
}
94+
95+
func (g *PlaygroundClient) TearDown(ctx context.Context) error {
96+
return errors.New("the teardown command is not valid for the Defang provider")
97+
}
98+
99+
func (g *PlaygroundClient) BootstrapList(context.Context) ([]string, error) {
100+
return nil, errors.New("this command is not valid for the Defang provider")
101+
}
102+
103+
func (g *PlaygroundClient) Restart(ctx context.Context, names ...string) (types.ETag, error) {
104+
// For now, we'll just get the service info and pass it back to Deploy as-is.
105+
services := make([]*defangv1.Service, 0, len(names))
106+
for _, name := range names {
107+
serviceInfo, err := g.GetService(ctx, &defangv1.ServiceID{Name: name})
108+
if err != nil {
109+
return "", err
110+
}
111+
services = append(services, serviceInfo.Service)
112+
}
113+
114+
dr, err := g.Deploy(ctx, &defangv1.DeployRequest{Services: services})
115+
if err != nil {
116+
return "", err
117+
}
118+
return dr.Etag, nil
119+
}
120+
121+
func (g PlaygroundClient) ServiceDNS(name string) string {
122+
whoami, _ := g.WhoAmI(context.TODO())
123+
return whoami.Tenant + "-" + name
124+
}
125+
126+
func (g PlaygroundClient) LoadProjectName() (string, error) {
127+
return string(g.tenantID), nil
128+
}

src/pkg/cli/connect.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ func Connect(cluster string, loader client.ProjectLoader) (*client.GrpcClient, t
7676
func NewClient(cluster string, provider client.Provider, loader client.ProjectLoader) client.Client {
7777
defangClient, tenantId := Connect(cluster, loader)
7878

79-
if provider == client.ProviderAWS {
79+
switch provider {
80+
case client.ProviderAWS:
8081
term.Info(" # Using AWS provider") // HACK: # prevents errors when evaluating the shell completion script
8182
byocClient := aws.NewByoc(tenantId, defangClient)
8283
return byocClient
84+
default:
85+
return &client.PlaygroundClient{*defangClient}
8386
}
84-
85-
return defangClient
8687
}
8788

8889
// Deprecated: don't rely on info in token

0 commit comments

Comments
 (0)