Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ jobs:
with:
go-version: 1.21.8

# The CLI embeds the Linux agents, which must have the same version as the CLI
- name: Build Linux agents
shell: bash
run: |
LDFLAGS="-s -w -X github.com/loft-sh/devpod/pkg/version.version=v${{ needs.create-release.outputs.original_package_version }} -X github.com/loft-sh/devpod/pkg/devcontainer/crane.craneSigningKey=${{ secrets.CRANE_PRIVATE_KEY }}" ./hack/build-agents.sh

- name: Build Sidecar CLI
if: matrix.settings.host != 'windows-latest'
run: |
Expand Down
20 changes: 11 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ go build ./...
go vet ./...
./hack/unit-tests.sh # what CI runs; `go test ./pkg/... ./cmd/...` is the quick version
make build # local CLI + desktop build via hack/rebuild.sh
./hack/build-agents.sh # the Linux agents the CLI embeds; run before `go build` of a CLI you want to use
```

Lint, the same way CI does (golangci-lint v1.60.1 cannot be built with the newest Go):
Expand Down Expand Up @@ -64,15 +65,16 @@ cd src-tauri && cargo +stable check
deep link scheme, the Flatpak id and existing installs.
- **Dependencies are vendored.** Builds use `-mod=vendor`. After changing imports or `go.mod`, run
`GOFLAGS=-mod=mod go mod tidy && go mod vendor` and commit `vendor/`.
- **The same binary runs on both sides.** The CLI injects itself as the agent into the machine/container (or the
agent downloads it from `curityio/devpod` releases). Structs serialized between them (`CLIOptions`,
`AgentWorkspaceInfo`, `ContainerWorkspaceInfo`, etc.) are a wire format between CLI and agent.
- **Dev builds can run a stale agent.** Unless the host is Linux with the container's arch (then the CLI injects
itself), the CLI injects `devpod-linux-<arch>` from `devpod-cache/` under Go's `os.TempDir()` (`$TMPDIR` on
macOS) and never refreshes a file that is already there. `hack/build-e2e.sh` and `hack/rebuild.sh` (when building
linux) copy fresh binaries there; if you build some other way, copy them yourself. Also, all dev builds report
version `v0.0.0`, so a container that already has an agent keeps it: recreate the workspace to test agent
changes.
- **The agent is embedded in the CLI.** `hack/build-agents.sh` builds the Linux agents (amd64 and arm64, with the
`devpod_agent` build tag) into `pkg/agent/agentbin/bin/`, and the CLI embeds them; it never downloads an agent.
The agent injects itself from the machine into the container. Without that script, `go build` makes a CLI with
no agents, which can't create workspaces (unless it's built for Linux, where it uses itself). DevPod replaces an
agent of another version, but state an older agent wrote on a machine or in a container (e.g. the serialized
`AgentWorkspaceInfo` and `ContainerWorkspaceInfo`) is still read by the new one.
- **Builds without a version keep a container's agent.** DevPod only replaces an agent whose version differs.
`hack/rebuild.sh` and `hack/build-e2e.sh` give each build its own version (`v0.0.0-dev.<UTC time>`, or `VERSION`),
shared by the CLI and its agents. A plain `hack/build-agents.sh` and `go build` both use `v0.0.0`, so a container
that already has a `v0.0.0` agent keeps it.
- **Don't import `k8s.io/client-go/kubernetes`** (or its typed clients, or anything that uses them, such as
go-containerregistry's `authn/kubernetes`). Its scheme links every Kubernetes API group and adds over 20 MB to
the binary, which also runs as the agent. Use `pkg/kubeclient`, which only registers core/v1 and rbac/v1; add a
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ Add new entries to the top of the "Unreleased" section.

### Changed

- The DevPod CLI embeds the Linux agent for amd64 and arm64 ([#19](https://github.com/curityio/devpod/pull/19)),
whatever platform it runs on, and copies it into machines and dev containers itself. It no longer downloads the
agent from GitHub releases, so the agent always has the same version as the CLI, and workspaces can be created
without access to GitHub. The `AGENT_URL` context option, the `DEVPOD_AGENT_URL` environment variable, the
provider's `agent.downloadURL` and the desktop app's "Agent URL" setting are removed.
- When DevPod replaces the agent of an existing dev container that a different DevPod version set up, it warns that
you may want to re-create the workspace with `devpod up --recreate`
([#19](https://github.com/curityio/devpod/pull/19)).
- The `devpod` binary is about 40% smaller ([#21](https://github.com/curityio/devpod/pull/21)): the stripped
linux/amd64 build went from 68 MB to 41 MB (20 MB to 14 MB gzipped). The Kubernetes driver and the in-cluster
registry keychain now use a small client for the core/v1 and rbac/v1 APIs instead of client-go's clientset,
Expand Down
23 changes: 12 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
## Development Setup

1. Clone the repository locally
2. If you want to change something in DevPod agent code:
1. Exchange the URL in [DefaultAgentDownloadURL](./pkg/agent/agent.go) with a
custom public repository release you have created.
2. Build devpod via: `./hack/rebuild.sh`
3. Upload `test/devpod-linux-amd64` and `test/devpod-linux-arm64` to the public
repository release assets.
3. Build devpod via: `./hack/rebuild.sh` (asking for sudo password)
4. Add docker provider via `devpod provider add docker`
5. Configure docker provider via `devpod use provider docker`
6. Start devpod in vscode with `devpod up examples/simple`
2. Build devpod via: `./hack/rebuild.sh` (asking for sudo password). It first builds the Linux agents with
`./hack/build-agents.sh`, which the CLI embeds and copies into machines and dev containers. Each build gets its
own version (`v0.0.0-dev.<UTC time>`), so DevPod replaces the agent in existing workspaces.
3. Add docker provider via `devpod provider add docker`
4. Configure docker provider via `devpod use provider docker`
5. Start devpod in vscode with `devpod up examples/simple`

## Build from source

Expand All @@ -21,7 +17,12 @@ Prerequisites CLI:
- [Go 1.20](https://go.dev/doc/install)

Once installed, run
`CGO_ENABLED=0 go build -ldflags "-s -w" -o devpod-cli`
`./hack/build-agents.sh && CGO_ENABLED=0 go build -ldflags "-s -w" -o devpod-cli`

This build has version `v0.0.0`, so DevPod won't replace a `v0.0.0` agent that an earlier build put into a
workspace. Without `./hack/build-agents.sh`, the CLI has no agent to copy into machines and dev containers (only a CLI built for
Linux can then use itself as the agent, for its own architecture). Pass the same `-ldflags` to both (as `LDFLAGS`
for the script), so that the agent has the same version as the CLI.

Prerequisites GUI:

Expand Down
2 changes: 1 addition & 1 deletion cmd/agent/workspace/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (cmd *LogsCmd) Run(ctx context.Context) error {
logger := log.Default.ErrorStreamOnly()

// create new runner
runner, err := devcontainer.NewRunner(agent.ContainerDevPodHelperLocation, agent.DefaultAgentDownloadURL(), workspaceInfo, logger)
runner, err := devcontainer.NewRunner(agent.ContainerDevPodHelperLocation, workspaceInfo, logger)
if err != nil {
return fmt.Errorf("create runner: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/agent/workspace/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (cmd *UpCmd) devPodUp(ctx context.Context, workspaceInfo *provider2.AgentWo
}

func CreateRunner(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (devcontainer.Runner, error) {
return devcontainer.NewRunner(agent.ContainerDevPodHelperLocation, agent.DefaultAgentDownloadURL(), workspaceInfo, log)
return devcontainer.NewRunner(agent.ContainerDevPodHelperLocation, workspaceInfo, log)
}

func InitContentFolder(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (bool, error) {
Expand Down
2 changes: 0 additions & 2 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ func buildAgentClient(ctx context.Context, workspaceClient client.WorkspaceClien
},
workspaceClient.AgentLocal(),
workspaceClient.AgentPath(),
workspaceClient.AgentURL(),
true,
command,
stdinReader,
stdoutWriter,
Expand Down
2 changes: 0 additions & 2 deletions cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ func (cmd *LogsCmd) Run(ctx context.Context, args []string) error {
},
client.AgentLocal(),
client.AgentPath(),
client.AgentURL(),
true,
sshServerCmd,
stdinReader,
stdoutWriter,
Expand Down
2 changes: 0 additions & 2 deletions cmd/machine/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ func (cmd *SSHCmd) Run(ctx context.Context, args []string) error {
},
machineClient.AgentLocal(),
machineClient.AgentPath(),
machineClient.AgentURL(),
true,
command,
stdin,
stdout,
Expand Down
2 changes: 0 additions & 2 deletions cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,6 @@ func (cmd *UpCmd) devPodUpMachine(
},
client.AgentLocal(),
client.AgentPath(),
client.AgentURL(),
true,
sshCmd,
sshTunnelStdinReader,
sshTunnelStdoutWriter,
Expand Down
5 changes: 1 addition & 4 deletions desktop/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,7 @@ export type TSupportedIDE = (typeof SUPPORTED_IDES)[number]
//#region Context
export type TContextOptions = Record<TContextOptionName, TContextOption>
// See pkg/config/context.go
export type TContextOptionName =
| "AGENT_URL"
| "SSH_INJECT_DOCKER_CREDENTIALS"
| "SSH_INJECT_GIT_CREDENTIALS"
export type TContextOptionName = "SSH_INJECT_DOCKER_CREDENTIALS" | "SSH_INJECT_GIT_CREDENTIALS"
export type TContextOption = Readonly<{
name: TContextOptionName
description: string | null | undefined
Expand Down
6 changes: 0 additions & 6 deletions desktop/src/views/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
} from "../../lib"
import { useWelcomeModal } from "../../useWelcomeModal"
import {
useAgentURLOption,
useDockerCredentialsForwardingOption,
useGitCredentialsForwardingOption,
} from "./useContextOptions"
Expand Down Expand Up @@ -88,7 +87,6 @@ export function Settings() {
function GeneralSettings() {
const { settings, set } = useChangeSettings()
const { modal: welcomeModal, show: showWelcomeModal } = useWelcomeModal()
const { input: agentURLInput, helpText: agentURLHelpText } = useAgentURLOption()
const { input: proxyInput, helpText: proxyHelpText } = useProxyOptions()
const {
badge: installCLIBadge,
Expand Down Expand Up @@ -127,10 +125,6 @@ function GeneralSettings() {
</Button>
</SettingSection>

<SettingSection title="Agent URL" description={agentURLHelpText}>
{agentURLInput}
</SettingSection>

<SettingSection title="Proxy Configuration" description={proxyHelpText}>
{proxyInput}
</SettingSection>
Expand Down
42 changes: 2 additions & 40 deletions desktop/src/views/Settings/useContextOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Code, Switch } from "@chakra-ui/react"
import { Switch } from "@chakra-ui/react"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { useCallback, useMemo } from "react"
import { useMemo } from "react"
import { client } from "../../client"
import { QueryKeys } from "../../queryKeys"
import { TContextOptionName } from "../../types"
import { ClearableInput } from "./ClearableInput"

const DEFAULT_DEVPOD_AGENT_URL = "https://github.com/curityio/devpod/releases/latest/download/"

export function useContextOptions() {
const queryClient = useQueryClient()
Expand All @@ -32,41 +29,6 @@ export function useContextOptions() {
)
}

export function useAgentURLOption() {
const { options, updateOption } = useContextOptions()

const handleChanged = useCallback(
(newValue: string) => {
const value = newValue.trim()
updateOption({ option: "AGENT_URL", value })
},
[updateOption]
)

const input = useMemo(
() => (
<ClearableInput
placeholder="Override Agent URL"
defaultValue={options?.AGENT_URL.value ?? ""}
onChange={handleChanged}
/>
),
[handleChanged, options?.AGENT_URL.value]
)

const helpText = useMemo(
() => (
<>
Set the Agent URL. If you leave this empty, it will be pulled from{" "}
<Code>{DEFAULT_DEVPOD_AGENT_URL}</Code>
</>
),
[]
)

return { input, helpText }
}

export function useDockerCredentialsForwardingOption() {
const { options, updateOption } = useContextOptions()

Expand Down
16 changes: 0 additions & 16 deletions e2e/e2e_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package e2e

import (
"os"
"runtime"
"testing"
"time"

"github.com/onsi/ginkgo/v2"

"github.com/onsi/gomega"

"github.com/loft-sh/devpod/e2e/framework"

// Register tests
_ "github.com/loft-sh/devpod/e2e/tests/build"
_ "github.com/loft-sh/devpod/e2e/tests/context"
Expand All @@ -30,17 +25,6 @@ import (
// generated in this directory, and cluster logs will also be saved.
// This function is called on each Ginkgo node in parallel mode.
func TestRunE2ETests(t *testing.T) {
if runtime.GOOS != "linux" {
go framework.ServeAgent()

// wait for http server to be up and running
for {
time.Sleep(time.Second)
if os.Getenv("DEVPOD_AGENT_URL") != "" {
break
}
}
}
gomega.RegisterFailHandler(ginkgo.Fail)
ginkgo.RunSpecs(t, "DevPod e2e suite")
}
85 changes: 0 additions & 85 deletions e2e/framework/server_utils.go

This file was deleted.

18 changes: 18 additions & 0 deletions hack/build-agents.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

# Builds the Linux agent binaries (amd64 and arm64) that get embedded into the devpod CLI, see pkg/agent/agentbin.
# Run it before building the CLI, with the same LDFLAGS (the version especially), so that the agent matches the CLI.
# Without LDFLAGS, the agents have version v0.0.0, like a plain `go build` of the CLI.

set -e

SRC_DIR="${SRCDIR:=.}"
LDFLAGS="${LDFLAGS:=-s -w}"
OUT_DIR="$SRC_DIR/pkg/agent/agentbin/bin"

for arch in amd64 arm64; do
echo "[INFO] Building agent for linux/$arch"
CGO_ENABLED=0 GOOS=linux GOARCH=$arch go build -tags devpod_agent -ldflags "$LDFLAGS" -o "$OUT_DIR/devpod-linux-$arch" "$SRC_DIR"
gzip -9 -n -f "$OUT_DIR/devpod-linux-$arch"
done
echo "[INFO] Built agents in $OUT_DIR"
Loading
Loading