Skip to content

Commit d4a42bf

Browse files
committed
feat(perms): migrate owner-based to workspace
1 parent 7a1e912 commit d4a42bf

57 files changed

Lines changed: 1296 additions & 1368 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/root.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func NewDryccCommand() *cobra.Command {
5454
rootCmd.AddCommand(parser.NewKeysCommand(&cmdr))
5555
rootCmd.AddCommand(parser.NewLabelsCommand(&cmdr))
5656
rootCmd.AddCommand(parser.NewLimitsCommand(&cmdr))
57-
rootCmd.AddCommand(parser.NewPermsCommand(&cmdr))
57+
rootCmd.AddCommand(parser.NewWorkspacesCommand(&cmdr))
5858
rootCmd.AddCommand(parser.NewPsCommand(&cmdr))
5959
rootCmd.AddCommand(parser.NewPtsCommand(&cmdr))
6060
rootCmd.AddCommand(parser.NewRegistryCommand(&cmdr))
@@ -68,7 +68,6 @@ func NewDryccCommand() *cobra.Command {
6868
rootCmd.AddCommand(parser.NewTLSCommand(&cmdr))
6969
rootCmd.AddCommand(parser.NewTokensCommand(&cmdr))
7070
rootCmd.AddCommand(parser.NewUpdateCommand(&cmdr))
71-
rootCmd.AddCommand(parser.NewUsersCommand(&cmdr))
7271
rootCmd.AddCommand(parser.NewVolumesCommand(&cmdr))
7372
rootCmd.AddCommand(parser.NewVersionCommand(&cmdr))
7473
// shortcuts

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.25
55
require (
66
github.com/chai2010/gettext-go v1.0.3
77
github.com/containerd/console v1.0.4
8-
github.com/drycc/controller-sdk-go v0.0.0-20251211045545-b196e6964a1c
8+
github.com/drycc/controller-sdk-go v0.0.0-20260416093543-28d3a22ab999
99
github.com/drycc/pkg v0.0.0-20250917064731-345368da3dbf
1010
github.com/minio/selfupdate v0.6.0
1111
github.com/olekukonko/tablewriter v0.0.5

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6N
99
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
1010
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
1111
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12-
github.com/drycc/controller-sdk-go v0.0.0-20251211045545-b196e6964a1c h1:v7dQdercvt0o+/dOeCpQSEYedvo2lTY8eCwHBxx48hg=
13-
github.com/drycc/controller-sdk-go v0.0.0-20251211045545-b196e6964a1c/go.mod h1:eHcmYwg81ASlP55/U587xnBZnZoeZnPHXGeQ8nYWnsg=
12+
github.com/drycc/controller-sdk-go v0.0.0-20260416093543-28d3a22ab999 h1:yHGZInF3xoLRHDgIPQFnfXF8EGaPZZXaRXf0I4pxnWI=
13+
github.com/drycc/controller-sdk-go v0.0.0-20260416093543-28d3a22ab999/go.mod h1:eHcmYwg81ASlP55/U587xnBZnZoeZnPHXGeQ8nYWnsg=
1414
github.com/drycc/pkg v0.0.0-20250917064731-345368da3dbf h1:CYy3NoPhfFhkGAbEppTOQfY/HC2s0FJDcBgbtRKeweg=
1515
github.com/drycc/pkg v0.0.0-20250917064731-345368da3dbf/go.mod h1:BrrNrNskHKm+nJYhXfGuI114w8nupi0AMo8QZHID7CM=
1616
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=

internal/commands/apps.go

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88
"time"
99

10+
"github.com/drycc/controller-sdk-go/api"
1011
"github.com/drycc/controller-sdk-go/apps"
1112
"github.com/drycc/controller-sdk-go/appsettings"
1213
"github.com/drycc/controller-sdk-go/domains"
@@ -19,14 +20,14 @@ import (
1920

2021
// AppCreate creates an app.
2122
func (d *DryccCmd) AppCreate(id, remote string, noRemote bool) error {
22-
s, err := settings.Load(d.ConfigFile)
23+
workspace, s, err := loader.LoadWorkspace(d.ConfigFile)
2324
if err != nil {
2425
return err
2526
}
2627

2728
d.Print("Creating Application... ")
2829
quit := progress(d.WOut)
29-
app, err := apps.New(s.Client, id)
30+
app, err := apps.New(s.Client, id, workspace)
3031

3132
quit <- true
3233
<-quit
@@ -59,7 +60,7 @@ func (d *DryccCmd) AppCreate(id, remote string, noRemote bool) error {
5960

6061
// AppsList lists apps on the Drycc controller.
6162
func (d *DryccCmd) AppsList(results int) error {
62-
s, err := settings.Load(d.ConfigFile)
63+
workspace, s, err := loader.LoadWorkspace(d.ConfigFile)
6364
if err != nil {
6465
return err
6566
}
@@ -68,16 +69,16 @@ func (d *DryccCmd) AppsList(results int) error {
6869
results = s.Limit
6970
}
7071

71-
apps, count, err := apps.List(s.Client, results)
72+
apps, count, err := apps.List(s.Client, workspace, results)
7273
if d.checkAPICompatibility(s.Client, err) != nil {
7374
return err
7475
}
7576
if count > 0 {
76-
table := d.getDefaultFormatTable([]string{"ID", "OWNER", "CREATED", "UPDATED"})
77+
table := d.getDefaultFormatTable([]string{"ID", "WORKSPACE", "CREATED", "UPDATED"})
7778
for _, app := range apps {
7879
table.Append([]string{
7980
app.ID,
80-
app.Owner,
81+
app.Workspace,
8182
d.formatTime(app.Created),
8283
d.formatTime(app.Updated),
8384
})
@@ -110,7 +111,7 @@ func (d *DryccCmd) AppInfo(appID string) error {
110111
table.Append([]string{"App:", app.ID})
111112
table.Append([]string{"URL:", url})
112113
table.Append([]string{"UUID:", app.UUID})
113-
table.Append([]string{"Owner:", app.Owner})
114+
table.Append([]string{"Workspace:", app.Workspace})
114115
table.Append([]string{"Created:", d.formatTime(app.Created)})
115116
table.Append([]string{"Updated:", d.formatTime(app.Updated)})
116117

@@ -279,16 +280,16 @@ func (d *DryccCmd) AppDestroy(appID, confirm string) error {
279280
return nil
280281
}
281282

282-
// AppTransfer transfers app ownership to another user.
283-
func (d *DryccCmd) AppTransfer(appID, username string) error {
283+
// AppTransfer transfers app to another workspace.
284+
func (d *DryccCmd) AppTransfer(appID, workspace string) error {
284285
appID, s, err := loader.LoadAppSettings(d.ConfigFile, appID)
285286
if err != nil {
286287
return err
287288
}
288289

289-
d.Printf("Transferring %s to %s... ", appID, username)
290+
d.Printf("Transferring %s to %s... ", appID, workspace)
290291

291-
err = apps.Transfer(s.Client, appID, username)
292+
err = apps.Transfer(s.Client, appID, workspace)
292293
if d.checkAPICompatibility(s.Client, err) != nil {
293294
return err
294295
}
@@ -306,23 +307,10 @@ func (d *DryccCmd) appURL(s *settings.Settings, appID string) (string, error) {
306307
if d.checkAPICompatibility(s.Client, err) != nil {
307308
return "", err
308309
}
309-
310-
if len(domains) == 0 {
311-
return "", nil
312-
}
313-
314-
return expandURL(s.Client.ControllerURL.Host, domains[0].Domain), nil
315-
}
316-
317-
// expandURL expands an app url if necessary.
318-
func expandURL(host, u string) string {
319-
if strings.Contains(u, ".") {
320-
// If domain is a full url.
321-
return u
310+
for _, domain := range domains {
311+
if domain.Ptype == api.PtypeWeb {
312+
return domain.Domain, nil
313+
}
322314
}
323-
324-
// If domain is a subdomain, look up the controller url and replace the subdomain.
325-
parts := strings.Split(host, ".")
326-
parts[0] = u
327-
return strings.Join(parts, ".")
315+
return "", nil
328316
}

internal/commands/apps_test.go

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ func TestAppsList(t *testing.T) {
2525
t.Fatal(err)
2626
}
2727
defer server.Close()
28+
29+
// Set workspace in config so AppsList can read it
30+
s, _ := settings.Load(cf)
31+
s.Workspace = "dolar-sit-amet"
32+
cf, _ = s.Save(cf)
33+
2834
var b bytes.Buffer
2935
cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
3036

@@ -38,7 +44,7 @@ func TestAppsList(t *testing.T) {
3844
{
3945
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
4046
"id": "lorem-ipsum",
41-
"owner": "dolar-sit-amet",
47+
"workspace": "dolar-sit-amet",
4248
"created": "2016-08-22T17:40:16Z",
4349
"updated": "2016-08-22T17:40:16Z",
4450
"structure": {
@@ -48,7 +54,7 @@ func TestAppsList(t *testing.T) {
4854
{
4955
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
5056
"id": "consectetur",
51-
"owner": "adipiscing",
57+
"workspace": "adipiscing",
5258
"created": "2016-08-22T17:40:16Z",
5359
"updated": "2016-08-22T17:40:16Z",
5460
"structure": {
@@ -61,19 +67,46 @@ func TestAppsList(t *testing.T) {
6167

6268
err = cmdr.AppsList(-1)
6369
assert.NoError(t, err)
64-
testutil.AssertOutput(t, b.String(), `ID OWNER CREATED UPDATED
70+
testutil.AssertOutput(t, b.String(), `ID WORKSPACE CREATED UPDATED
6571
lorem-ipsum dolar-sit-amet 2016-08-22T17:40:16Z 2016-08-22T17:40:16Z
6672
consectetur adipiscing 2016-08-22T17:40:16Z 2016-08-22T17:40:16Z
6773
`)
6874
}
6975

76+
func TestAppsListNoWorkspace(t *testing.T) {
77+
t.Parallel()
78+
cf, _, err := testutil.NewTestServerAndClient()
79+
if err != nil {
80+
t.Fatal(err)
81+
}
82+
83+
// Clear workspace from config
84+
s, _ := settings.Load(cf)
85+
s.Workspace = ""
86+
cf, _ = s.Save(cf)
87+
88+
var b bytes.Buffer
89+
cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
90+
91+
// When no default workspace in config, should return error
92+
err = cmdr.AppsList(-1)
93+
assert.Error(t, err)
94+
assert.Contains(t, err.Error(), "no workspace specified")
95+
}
96+
7097
func TestAppsListLimit(t *testing.T) {
7198
t.Parallel()
7299
cf, server, err := testutil.NewTestServerAndClient()
73100
if err != nil {
74101
t.Fatal(err)
75102
}
76103
defer server.Close()
104+
105+
// Set workspace in config so AppsList can read it
106+
s, _ := settings.Load(cf)
107+
s.Workspace = "dolar-sit-amet"
108+
cf, _ = s.Save(cf)
109+
77110
var b bytes.Buffer
78111
cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
79112

@@ -87,7 +120,7 @@ func TestAppsListLimit(t *testing.T) {
87120
{
88121
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
89122
"id": "lorem-ipsum",
90-
"owner": "dolar-sit-amet",
123+
"workspace": "dolar-sit-amet",
91124
"created": "2016-08-22T17:40:16Z",
92125
"updated": "2016-08-22T17:40:16Z",
93126
"structure": {
@@ -100,7 +133,7 @@ func TestAppsListLimit(t *testing.T) {
100133

101134
err = cmdr.AppsList(1)
102135
assert.NoError(t, err)
103-
testutil.AssertOutput(t, b.String(), `ID OWNER CREATED UPDATED
136+
testutil.AssertOutput(t, b.String(), `ID WORKSPACE CREATED UPDATED
104137
lorem-ipsum dolar-sit-amet 2016-08-22T17:40:16Z 2016-08-22T17:40:16Z
105138
`)
106139
}
@@ -120,7 +153,7 @@ func TestAppsInfo(t *testing.T) {
120153
fmt.Fprintf(w, `{
121154
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
122155
"id": "lorem-ipsum",
123-
"owner": "dolar-sit-amet",
156+
"workspace": "dolar-sit-amet",
124157
"structure": {
125158
"cmd": 1
126159
},
@@ -189,7 +222,7 @@ func TestAppsInfo(t *testing.T) {
189222
testutil.AssertOutput(t, b.String(), `App: lorem-ipsum
190223
URL: `+url+`
191224
UUID: c4aed81c-d1ca-4ff1-ab89-d2151264e1a3
192-
Owner: dolar-sit-amet
225+
Workspace: dolar-sit-amet
193226
Created: 2016-08-22T17:40:16Z
194227
Updated: 2016-08-22T17:40:16Z
195228
Processes:
@@ -223,7 +256,7 @@ func TestAppDestroy(t *testing.T) {
223256
fmt.Fprintf(w, `{
224257
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
225258
"id": "lorem-ipsum",
226-
"owner": "dolar-sit-amet",
259+
"workspace": "dolar-sit-amet",
227260
"structure": {
228261
"cmd": 1
229262
},
@@ -256,7 +289,7 @@ func TestAppTransfer(t *testing.T) {
256289
fmt.Fprintf(w, `{
257290
"uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
258291
"id": "lorem-ipsum",
259-
"owner": "dolar-sit-amet",
292+
"workspace": "dolar-sit-amet",
260293
"structure": {
261294
"cmd": 1
262295
},
@@ -271,34 +304,18 @@ func TestAppTransfer(t *testing.T) {
271304
`, "output")
272305
}
273306

274-
func TestExpandUrl(t *testing.T) {
275-
checks := []expandURLCases{
276-
{
277-
Input: "test.com",
278-
Expected: "test.com",
279-
},
280-
{
281-
Input: "test",
282-
Expected: "test.foo.com",
283-
},
284-
}
285-
286-
for _, check := range checks {
287-
out := expandURL("drycc.foo.com", check.Input)
288-
289-
if out != check.Expected {
290-
t.Errorf("Expected %s, Got %s", check.Expected, out)
291-
}
292-
}
293-
}
294-
295307
func TestRemoteExists(t *testing.T) {
296308
cf, server, err := testutil.NewTestServerAndClient()
297309
if err != nil {
298310
t.Fatal(err)
299311
}
300312
defer server.Close()
301313

314+
// Set workspace in config so AppCreate can read it
315+
s, _ := settings.Load(cf)
316+
s.Workspace = "test-workspace"
317+
cf, _ = s.Save(cf)
318+
302319
server.Mux.HandleFunc("/v2/apps/", func(w http.ResponseWriter, _ *http.Request) {
303320
testutil.SetHeaders(w)
304321
fmt.Fprintf(w, `{
@@ -329,6 +346,6 @@ func TestRemoteExists(t *testing.T) {
329346
// Check that an error occurred and it contains the remote name
330347
// This works for any language since the remote name "drycc" is always in the error
331348
assert.Error(t, err)
332-
assert.Contains(t, err.Error(), "drycc",
349+
assert.Contains(t, err.Error(), "drycc",
333350
"error message should contain the remote name 'drycc', got: %s", err.Error())
334351
}

internal/commands/auth.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ func (d *DryccCmd) Whoami(all bool) error {
6262
}
6363
d.Println(user)
6464
} else {
65-
d.Printf("You are %s at %s\n", s.Username, s.Client.ControllerURL.String())
65+
if s.Workspace != "" {
66+
d.Printf("You are %s at %s, workspace %s\n", s.Username, s.Client.ControllerURL.String(), s.Workspace)
67+
} else {
68+
d.Printf("You are %s at %s\n", s.Username, s.Client.ControllerURL.String())
69+
}
6670
}
6771
return nil
6872
}

0 commit comments

Comments
 (0)