Skip to content

Commit 346e8a5

Browse files
authored
Enhance ENVITE setup process with runtime information integration (#25)
* Enhance ENVITE setup process with runtime information integration - Updated network and component logic to utilize runtime information for hostname and network latency. - Modified validation and update functions to reflect changes in the hosts file with dynamic hostname. - Improved user messages in setup files to include runtime-specific details for better clarity during initial setup. - Add wait time for Colima container start to allow network binding to kick in. * Add Colima runtime support in Docker configuration - Introduced a new runtime entry for Colima, including its socket path, internal hostname, and network latency. - Updated the fallback behavior in the runtime detection function to return a default 'Unknown' runtime when no matches are found. * Integrate RuntimeInfo into Component and Network structures - Added RuntimeInfo field to Component and Network types to enhance runtime-specific functionality. - Updated newComponent and NewNetwork functions to accept RuntimeInfo, improving the handling of network latency and internal hostnames. - Refactored Start method in Component to utilize the new RuntimeInfo field for network latency management. * Improve error handling in API and environment functions - Improved error handling with error wrapping to provide better error messages - Updated changeslog and readme * chagelog
1 parent 2bb4abe commit 346e8a5

File tree

14 files changed

+201
-60
lines changed

14 files changed

+201
-60
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.0.11](https://github.com/PerimeterX/envite/compare/v0.0.10...v0.0.11)
9+
10+
### Added
11+
12+
- Added docker runtime awareness with support for the following:
13+
- Docker Desktop
14+
- Colima (with 3-second network latency)
15+
- Podman
16+
- Rancher Desktop
17+
- Lima
18+
- OrbStack
19+
- Minikube
20+
- ContainerD
21+
- Finch
22+
- `ExtractRuntimeInfo` function to detect runtime type from Docker client info
23+
- Runtime-specific internal hostname mapping (e.g., `host.docker.internal`, `host.lima.internal`)
24+
- Network latency configuration for runtimes that require startup delays
25+
- Improved error handling with error wrapping to provide better error messages
26+
827
## [0.0.10](https://github.com/PerimeterX/envite/compare/v0.0.9...v0.0.10)
928

1029
### Fixed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ A framework to manage development and testing environments.
3535
- [Flags and Options](#flags-and-options)
3636
- [Adding Custom Components](#adding-custom-components)
3737
* [Key Elements of ENVITE](#key-elements-of-envite)
38+
* [Runtime Awareness](#runtime-awareness)
3839
* [Local Development](#local-development)
3940
* [Contact and Contribute](#contact-and-contribute)
4041
* [ENVITE Logo](#envite-logo)
@@ -334,6 +335,12 @@ functional environment.
334335
* `Component` Graph: Organizes components into layers and defines their relationships.
335336
* `Server`: Allow serving a UI to manage the environment.
336337

338+
## Runtime Awareness
339+
340+
ENVITE automatically detects and adapts to different Docker-compatible runtimes (Docker Desktop, Colima, Podman, Rancher Desktop, Lima, OrbStack, Minikube, ContainerD, and Finch). This runtime awareness allows ENVITE to handle runtime-specific behaviors automatically.
341+
342+
> Colima has some latency when attaching networking stack of new containers. This may lead to issue when adding log message based waiters. As a workaround, ENVITE adds a 3-second wait time after creating containers, to allow colima to finalize networking. This may not work perfectly as it depends on the time it takes colima to complete.
343+
337344
## Local Development
338345

339346
To locally work on ENVITE UI, cd into the `ui` dir and run react dev server using `npm start`.

api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ type GetStatusResponseComponent struct {
7676
func buildComponentInfo(c Component) (map[string]any, error) {
7777
data, err := json.Marshal(c.Config())
7878
if err != nil {
79-
return nil, err
79+
return nil, fmt.Errorf("failed to marshal component config: %w", err)
8080
}
8181

8282
var result map[string]any
8383
err = json.Unmarshal(data, &result)
8484
if err != nil {
85-
return nil, err
85+
return nil, fmt.Errorf("failed to unmarshal component config: %w", err)
8686
}
8787

8888
if result == nil {

cmd/envite/environment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func extractComponentType(err error, data []byte) (string, error) {
162162
}
163163
err = json.Unmarshal(data, &t)
164164
if err != nil {
165-
return "", err
165+
return "", fmt.Errorf("could not unmarshal component type: %w", err)
166166
}
167167

168168
return t.Type, nil

docker/component.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import (
99
"context"
1010
"encoding/json"
1111
"fmt"
12+
"math"
13+
"strings"
14+
"sync"
15+
"sync/atomic"
16+
"time"
17+
1218
"github.com/docker/docker/api/types"
1319
"github.com/docker/docker/api/types/container"
1420
"github.com/docker/docker/api/types/filters"
@@ -18,11 +24,6 @@ import (
1824
"github.com/docker/docker/pkg/jsonmessage"
1925
"github.com/docker/docker/pkg/stdcopy"
2026
"github.com/perimeterx/envite"
21-
"math"
22-
"strings"
23-
"sync"
24-
"sync/atomic"
25-
"time"
2627
)
2728

2829
// ComponentType is the type identifier for the Docker component.
@@ -33,6 +34,7 @@ type Component struct {
3334
lock sync.Mutex
3435
envID string
3536
cli *client.Client
37+
runtimeInfo *RuntimeInfo
3638
config Config
3739
runConfig *runConfig
3840
network *Network
@@ -48,21 +50,23 @@ type Component struct {
4850
// docker components must be instantiated via a Network.
4951
func newComponent(
5052
cli *client.Client,
53+
runtimeInfo *RuntimeInfo,
5154
envID string,
5255
network *Network,
5356
config Config,
5457
) (*Component, error) {
5558
imageCloneTag := fmt.Sprintf("%s_%s", config.Image, envID)
5659
runConf, err := config.initialize(network, imageCloneTag)
5760
if err != nil {
58-
return nil, err
61+
return nil, fmt.Errorf("failed to initialize component config: %w", err)
5962
}
6063

6164
containerName := fmt.Sprintf("%s_%s", envID, config.Name)
6265
network.configure(config, runConf, containerName)
6366

6467
c := &Component{
6568
cli: cli,
69+
runtimeInfo: runtimeInfo,
6670
config: config,
6771
envID: envID,
6872
runConfig: runConf,
@@ -176,6 +180,9 @@ func (c *Component) Start(ctx context.Context) error {
176180
}
177181

178182
c.monitorStartingStatus(id, true)
183+
if c.runtimeInfo.NetworkLatency > 0 {
184+
time.Sleep(c.runtimeInfo.NetworkLatency)
185+
}
179186
return nil
180187
}
181188

@@ -195,19 +202,19 @@ func (c *Component) startContainer(ctx context.Context) (string, error) {
195202
if err == nil {
196203
id = res.ID
197204
} else if !errdefs.IsConflict(err) {
198-
return "", err
205+
return "", fmt.Errorf("failed to create container: %w", err)
199206
} else {
200207
cont, err := c.findContainer(ctx)
201208
if err != nil {
202-
return "", err
209+
return "", fmt.Errorf("failed to find container: %w", err)
203210
}
204211

205212
id = cont.ID
206213
}
207214

208215
err = c.cli.ContainerStart(context.Background(), id, container.StartOptions{})
209216
if err != nil {
210-
return "", err
217+
return "", fmt.Errorf("failed to start container: %w", err)
211218
}
212219

213220
go c.writeLogs(id)
@@ -279,7 +286,7 @@ func (c *Component) Status(context.Context) (envite.ComponentStatus, error) {
279286
// check if container stopped
280287
cont, err := c.findContainer(context.Background())
281288
if err != nil {
282-
return "", err
289+
return "", fmt.Errorf("failed to find container: %w", err)
283290
}
284291

285292
if cont == nil || cont.State != "running" {
@@ -316,7 +323,7 @@ func (c *Component) Config() any {
316323
func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
317324
cont, err := c.findContainer(ctx)
318325
if err != nil {
319-
return 0, err
326+
return 0, fmt.Errorf("failed to find container: %w", err)
320327
}
321328

322329
c.Writer().WriteString(c.Writer().Color.Cyan(fmt.Sprintf("executing: %s", strings.Join(cmd, " "))))
@@ -327,12 +334,12 @@ func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
327334
AttachStderr: true,
328335
})
329336
if err != nil {
330-
return 0, err
337+
return 0, fmt.Errorf("failed to create exec: %w", err)
331338
}
332339

333340
hijack, err := c.cli.ContainerExecAttach(ctx, response.ID, types.ExecStartCheck{})
334341
if err != nil {
335-
return 0, err
342+
return 0, fmt.Errorf("failed to attach exec: %w", err)
336343
}
337344

338345
scanner := bufio.NewScanner(hijack.Reader)
@@ -344,7 +351,7 @@ func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
344351

345352
execResp, err := c.cli.ContainerExecInspect(ctx, response.ID)
346353
if err != nil {
347-
return 0, err
354+
return 0, fmt.Errorf("failed to inspect exec: %w", err)
348355
}
349356

350357
c.Writer().WriteString(c.Writer().Color.Cyan(fmt.Sprintf("exit code: %d", execResp.ExitCode)))
@@ -357,7 +364,7 @@ func (c *Component) findContainer(ctx context.Context) (*types.Container, error)
357364
Filters: filters.NewArgs(filters.Arg("name", c.containerName)),
358365
})
359366
if err != nil {
360-
return nil, err
367+
return nil, fmt.Errorf("failed to list containers: %w", err)
361368
}
362369

363370
for _, co := range containers {

docker/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ func (c Config) imagePullOptions() (image.PullOptions, error) {
652652
var err error
653653
auth, err = c.ImagePullOptions.RegistryAuthFunc()
654654
if err != nil {
655-
return image.PullOptions{}, err
655+
return image.PullOptions{}, fmt.Errorf("failed to get registry auth: %w", err)
656656
}
657657
} else {
658658
auth = c.ImagePullOptions.RegistryAuth

0 commit comments

Comments
 (0)