Skip to content

Commit 9a400eb

Browse files
authored
[bugfix, cleanup] Finish moving plugin services to process compose (#1150)
## Summary Removes `services` stanza from the plugin's json definition, in favor of using `process-compose.yaml`. * Fixes bug where, in doing `devbox services ls`, we would only return the _first_ service defined in a plugin, and would call it the name of the plugin (instead of the name of the service). This had some downstream effects as well. * Removes creation of wrappers of the form `<svc>-start|stop-service`. They were using the json-based definitions of the services, but `devbox service start <svc>` was using the process-compose definition, so they could diverge. Some wrappers were not being generated either, due to the bug above. * Deletes obsolete code. * Updates plugins that define services and bump their versions. Since plugins are packaged in the CLI, and the process-compose yamls were already being written before this change, I think this change is backwards-compatible when it comes to plugins. Reviewers, please advise on whether this change would affect service port-forwarding. ## How was it tested? Ran `devbox services ls|start|stop|up` with different plugins installed and verified they worked as expected. ## Backwards-compatible? NO, because we're removing the service wrappers (e.g. `redis-start-service`). I don't think they're being used, but @mikeland86 please confirm? If needed, I can replace them with `devbox services start redis` or something like that.
1 parent 53bfde9 commit 9a400eb

File tree

19 files changed

+50
-220
lines changed

19 files changed

+50
-220
lines changed

docs/app/docs/devbox_examples/languages/php.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Use `devbox services start|stop php-fpm` to start PHP-FPM in the background.
5353
```bash
5454
PHPFPM_PORT=8082
5555
PHPFPM_ERROR_LOG_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.log
56-
PHPFPM_PID_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.log
56+
PHPFPM_PID_FILE={PROJECT_DIR}/.devbox/virtenv/php/php-fpm.pid
5757
PHPRC={PROJECT_DIR}/devbox.d/php/php.ini
5858
```
5959

@@ -62,4 +62,4 @@ PHPRC={PROJECT_DIR}/devbox.d/php/php.ini
6262
* {PROJECT_DIR}/devbox.d/php81/php-fpm.conf
6363
* {PROJECT_DIR}/devbox.d/php81/php.ini
6464

65-
You can modify these file to configure PHP or your PHP-FPM server
65+
You can modify these files to configure PHP or your PHP-FPM server

internal/impl/devbox.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ func (d *Devbox) Services() (services.Services, error) {
501501
return nil, err
502502
}
503503

504-
userSvcs := services.FromProcessComposeYaml(d.projectDir)
504+
userSvcs := services.FromUserProcessCompose(d.projectDir)
505505

506506
svcSet := lo.Assign(pluginSvcs, userSvcs)
507507
keys := make([]string, 0, len(svcSet))
@@ -516,7 +516,6 @@ func (d *Devbox) Services() (services.Services, error) {
516516
}
517517

518518
return result, nil
519-
520519
}
521520

522521
func (d *Devbox) StartServices(ctx context.Context, serviceNames ...string) error {

internal/plugin/files.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ func getConfigIfAny(pkg *nix.Input, projectDir string) (*config, error) {
1818
return nil, errors.WithStack(err)
1919
}
2020

21-
// Try to find perfect match first
2221
for _, file := range configFiles {
2322
if file.IsDir() || strings.HasSuffix(file.Name(), ".go") {
2423
continue
2524
}
25+
// Try to find perfect match first
2626
content, err := plugins.BuiltIn.ReadFile(file.Name())
2727
if err != nil {
2828
return nil, errors.WithStack(err)

internal/plugin/info.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,19 @@ func printReadme(cfg *config, w io.Writer, markdown bool) error {
6363
}
6464

6565
func printServices(cfg *config, w io.Writer, markdown bool) error {
66-
if len(cfg.Services) == 0 {
66+
svcs, err := cfg.Services()
67+
if err != nil {
68+
return errors.WithStack(err)
69+
}
70+
if len(svcs) == 0 {
6771
return nil
6872
}
6973
services := ""
70-
for _, service := range cfg.Services {
74+
for _, service := range svcs {
7175
services += fmt.Sprintf("* %[1]s\n", service.Name)
7276
}
7377

74-
_, err := fmt.Fprintf(
78+
_, err = fmt.Fprintf(
7579
w,
7680
"%sServices:\n%s\nUse `devbox services start|stop [service]` to interact with services\n\n",
7781
lo.Ternary(markdown, "### ", ""),

internal/plugin/plugin.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ type config struct {
4343
Packages []string `json:"packages"`
4444
Env map[string]string `json:"env"`
4545
Readme string `json:"readme"`
46-
Services services.Services `json:"services"`
4746

4847
Shell struct {
4948
// InitHook contains commands that will run at shell startup.
@@ -60,6 +59,13 @@ func (c *config) ProcessComposeYaml() (string, bool) {
6059
return "", false
6160
}
6261

62+
func (c *config) Services() (services.Services, error) {
63+
if file, ok := c.ProcessComposeYaml(); ok {
64+
return services.FromProcessCompose(file)
65+
}
66+
return nil, nil
67+
}
68+
6369
func (m *Manager) Include(included string) error {
6470
name, err := m.parseInclude(included)
6571
if err != nil {

internal/plugin/services.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
package plugin
55

66
import (
7+
"fmt"
8+
"os"
9+
710
"go.jetpack.io/devbox/internal/nix"
811
"go.jetpack.io/devbox/internal/services"
912
)
1013

11-
// TODO: this should have PluginManager as receiver so we can build once with
12-
// pkgs, includes, etc
1314
func (m *Manager) GetServices(
1415
pkgs []*nix.Input,
1516
includes []string,
1617
) (services.Services, error) {
17-
svcs := services.Services{}
18+
allSvcs := services.Services{}
1819

1920
allPkgs := append([]*nix.Input(nil), pkgs...)
2021
for _, include := range includes {
@@ -34,15 +35,15 @@ func (m *Manager) GetServices(
3435
continue
3536
}
3637

37-
if file, ok := conf.ProcessComposeYaml(); ok {
38-
svc := services.Service{
39-
Name: conf.Name,
40-
Env: conf.Env,
41-
ProcessComposePath: file,
42-
}
43-
svcs[conf.Name] = svc
38+
svcs, err := conf.Services()
39+
if err != nil {
40+
fmt.Fprintf(os.Stderr, "error reading services in plugin \"%s\", skipping", conf.Name)
41+
continue
42+
}
43+
for name, svc := range svcs {
44+
allSvcs[name] = svc
4445
}
45-
4646
}
47-
return svcs, nil
47+
48+
return allSvcs, nil
4849
}

internal/services/config.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ import (
1414
"go.jetpack.io/devbox/internal/cuecfg"
1515
)
1616

17-
func FromProcessComposeYaml(projectDir string) Services {
18-
// TODO need to handle if a filepath is passed in
17+
func FromUserProcessCompose(projectDir string) Services {
1918
processComposeYaml := lookupProcessCompose(projectDir, "")
2019
if processComposeYaml == "" {
2120
return nil
2221
}
23-
userSvcs, err := readProcessCompose(processComposeYaml)
22+
23+
userSvcs, err := FromProcessCompose(processComposeYaml)
2424
if err != nil {
2525
fmt.Fprintf(os.Stderr, "error reading process-compose.yaml: %s, skipping", err)
2626
return nil
2727
}
2828
return userSvcs
2929
}
3030

31-
func readProcessCompose(path string) (Services, error) {
31+
func FromProcessCompose(path string) (Services, error) {
3232
processCompose := &types.Project{}
3333
services := Services{}
3434
err := errors.WithStack(cuecfg.ParseFile(path, processCompose))

internal/services/manager.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,7 @@ func StartProcessManager(
167167
}
168168

169169
for _, s := range availableServices {
170-
if file, hasComposeYaml := s.ProcessComposeYaml(); hasComposeYaml {
171-
flags = append(flags, "-f", file)
172-
}
170+
flags = append(flags, "-f", s.ProcessComposePath)
173171
}
174172

175173
if processComposeBackground {

internal/services/services.go

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,11 @@
11
// Copyright 2023 Jetpack Technologies Inc and contributors. All rights reserved.
22
// Use of this source code is governed by the license in the LICENSE file.
33

4-
//lint:file-ignore U1000 Ignore unused function temporarily for debugging
54
package services
65

7-
import (
8-
"encoding/json"
9-
"fmt"
10-
"io"
11-
"os"
12-
13-
"github.com/a8m/envsubst"
14-
"github.com/fatih/color"
15-
"github.com/pkg/errors"
16-
17-
"go.jetpack.io/devbox/internal/envir"
18-
)
19-
20-
type Services map[string]Service
6+
type Services map[string]Service // name -> Service
217

228
type Service struct {
23-
Name string `json:"name"`
24-
Env map[string]string `json:"-"`
25-
RawPort string `json:"port"`
26-
Start string `json:"start"`
27-
Stop string `json:"stop"`
9+
Name string
2810
ProcessComposePath string
2911
}
30-
31-
// TODO: (john) Since moving to process-compose, our services no longer use the old `toggleServices` function. We'll need to clean a lot of this up in a later PR.
32-
33-
type serviceAction int
34-
35-
const (
36-
startService serviceAction = iota
37-
stopService
38-
)
39-
40-
func printProxyURL(w io.Writer, services Services) error { // TODO: remove it?
41-
if !envir.IsDevboxCloud() {
42-
return nil
43-
}
44-
45-
hostname, err := os.Hostname()
46-
if err != nil {
47-
return errors.WithStack(err)
48-
}
49-
50-
printGeneric := false
51-
for _, service := range services {
52-
if port, _ := service.Port(); port != "" {
53-
color.New(color.FgHiGreen).Fprintf(
54-
w,
55-
"To access %s on this vm use: %s-%s.svc.devbox.sh\n",
56-
service.Name,
57-
hostname,
58-
port,
59-
)
60-
} else {
61-
printGeneric = true
62-
}
63-
}
64-
65-
if printGeneric {
66-
color.New(color.FgHiGreen).Fprintf(
67-
w,
68-
"To access other services on this vm use: %s-<port>.svc.devbox.sh\n",
69-
hostname,
70-
)
71-
}
72-
return nil
73-
}
74-
75-
func (s *Service) Port() (string, error) {
76-
if s.RawPort == "" {
77-
return "", nil
78-
}
79-
return envsubst.String(s.RawPort)
80-
}
81-
82-
func (s *Service) ProcessComposeYaml() (string, bool) {
83-
return s.ProcessComposePath, true
84-
}
85-
86-
func (s *Service) StartName() string {
87-
return fmt.Sprintf("%s-service-start", s.Name)
88-
}
89-
90-
func (s *Service) StopName() string {
91-
return fmt.Sprintf("%s-service-stop", s.Name)
92-
}
93-
94-
func (s *Services) UnmarshalJSON(b []byte) error {
95-
var m map[string]Service
96-
if err := json.Unmarshal(b, &m); err != nil {
97-
return err
98-
}
99-
*s = make(Services)
100-
for name, svc := range m {
101-
svc.Name = name
102-
(*s)[name] = svc
103-
}
104-
return nil
105-
}

internal/wrapnix/wrapper.go

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ import (
1616
"go.jetpack.io/devbox/internal/cmdutil"
1717
"go.jetpack.io/devbox/internal/nix"
1818
"go.jetpack.io/devbox/internal/plugin"
19-
"go.jetpack.io/devbox/internal/services"
2019
)
2120

2221
type devboxer interface {
2322
NixBins(ctx context.Context) ([]string, error)
2423
ShellEnvHash(ctx context.Context) (string, error)
2524
ShellEnvHashKey() string
2625
ProjectDir() string
27-
Services() (services.Services, error)
2826
}
2927

3028
//go:embed wrapper.sh.tmpl
@@ -38,11 +36,6 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
3836
return err
3937
}
4038

41-
services, err := devbox.Services()
42-
if err != nil {
43-
return err
44-
}
45-
4639
// Remove all old wrappers
4740
_ = os.RemoveAll(filepath.Join(devbox.ProjectDir(), plugin.WrapperPath))
4841

@@ -51,28 +44,6 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
5144
_ = os.MkdirAll(destPath, 0755)
5245

5346
bashPath := cmdutil.GetPathOrDefault("bash", "/bin/bash")
54-
for _, service := range services {
55-
if err = createWrapper(&createWrapperArgs{
56-
devboxer: devbox,
57-
BashPath: bashPath,
58-
Command: service.Start,
59-
Env: service.Env,
60-
ShellEnvHash: shellEnvHash,
61-
destPath: filepath.Join(destPath, service.StartName()),
62-
}); err != nil {
63-
return err
64-
}
65-
if err = createWrapper(&createWrapperArgs{
66-
devboxer: devbox,
67-
BashPath: bashPath,
68-
Command: service.Stop,
69-
Env: service.Env,
70-
ShellEnvHash: shellEnvHash,
71-
destPath: filepath.Join(destPath, service.StopName()),
72-
}); err != nil {
73-
return err
74-
}
75-
}
7647

7748
bins, err := devbox.NixBins(ctx)
7849
if err != nil {

plugins/README.md

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,16 @@ Plugins are defined as JSON Template files, using the following schema:
3838
"<key>": "<value>"
3939
},
4040
"create_files": {
41-
"<destination>": "<source>",
41+
"<destination>": "<source>"
4242
},
4343
"init_hook": [
4444
"<bash commands>"
45-
],
46-
"services": {
47-
"service_name": {
48-
"start": "<start_command>",
49-
"stop": "<stop_command>",
50-
"port": <number>
51-
}
52-
}
45+
]
5346
}
5447
```
5548

49+
A plugin can define services by adding a `process-compose.yaml` file in its `create_files` stanza. See process compose [docs](https://github.com/F1bonacc1/process-compose) or existing plugins in this directory for examples.
50+
5651
### Plugin Lifecycle
5752

5853
Plugins are activated whenever a developer runs `devbox shell`, runs a script with `devbox run`, or starts a service using `devbox services start|restart`. The lifecycle of a devbox shell with plugins goes in the following order.
@@ -122,12 +117,6 @@ You should use this to copy starter config files or templates needed to run the
122117

123118
A single `bash` command or list of `bash` commands that should run before the user's shell is initialized. This will run every time a shell is started, so you should avoid any resource heavy or long running processes in this step.
124119

125-
#### `services` *object*
126-
127-
A map of services that your plugin exposes to the user through `devbox services`. Services should have a `start` command and `stop` command defined so that Devbox can safely start and stop your service. You can optionally specify a `port` for Devbox to use along with automatic port forwarding in Devbox Cloud
128-
129-
For more details, see our [Services Documentation](https://www.jetpack.io/devbox/docs/guides/services/)
130-
131120
## Tips for Writing Plugins
132121

133122
* Only add plugins for packages that require configuration to work with Devbox.

plugins/apacheHttpd.json

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "apache",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"match": "^(apache|apacheHttpd)$",
55
"readme": "If you with to edit the config file, please copy it out of the .devbox directory.",
66
"env": {
@@ -14,12 +14,5 @@
1414
"{{ .DevboxDir }}/httpd.conf": "apache/httpd.conf",
1515
"{{ .DevboxDirRoot }}/web/index.html": "web/index.html",
1616
"{{ .Virtenv }}/process-compose.yaml": "apache/process-compose.yaml"
17-
},
18-
"services": {
19-
"apache": {
20-
"port": "$HTTPD_PORT",
21-
"start": "apachectl start -f $HTTPD_CONFDIR/httpd.conf",
22-
"stop": "apachectl stop -f $HTTPD_CONFDIR/httpd.conf"
23-
}
2417
}
2518
}

0 commit comments

Comments
 (0)