Skip to content
Open
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
5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build build-server build-panda build-proxy install install-server install-panda install-proxy test lint clean docker docker-push docker-sandbox test-sandbox run studio help setup-hooks govulncheck generate
.PHONY: build build-server build-panda build-proxy install install-server install-panda install-proxy test lint clean docker docker-push docker-sandbox test-sandbox run studio help setup-hooks govulncheck

# Build variables
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
Expand Down Expand Up @@ -61,9 +61,6 @@ govulncheck: ## Scan for reachable vulnerabilities (allowlist in scripts/govulnc
tidy: ## Run go mod tidy
go mod tidy

generate: ## Run code generation (oapi-codegen for the compute API client)
go generate ./pkg/compute/...

clean: ## Clean build artifacts
rm -f panda-server .panda-server-bin panda panda-proxy panda-server-linux-amd64
rm -f coverage.out coverage.html
Expand Down
14 changes: 3 additions & 11 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ require (
github.com/minio/minio-go/v7 v7.2.1
github.com/moby/moby/api v1.54.2
github.com/moby/moby/client v0.4.1
github.com/oapi-codegen/runtime v1.3.1
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
github.com/redis/go-redis/v9 v9.20.0
Expand All @@ -32,7 +31,6 @@ require (
github.com/stretchr/testify v1.11.1
github.com/testcontainers/testcontainers-go v0.42.0
github.com/yuin/goldmark v1.8.2
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/sys v0.45.0
golang.org/x/time v0.15.0
google.golang.org/protobuf v1.36.11
Expand All @@ -57,7 +55,6 @@ require (
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/fatih/color v1.19.0 // indirect
Expand Down Expand Up @@ -102,7 +99,7 @@ require (
github.com/moby/term v0.5.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oapi-codegen/oapi-codegen/v2 v2.7.1 // indirect
github.com/oapi-codegen/runtime v1.3.1 // indirect
github.com/oasdiff/yaml v0.0.9 // indirect
github.com/oasdiff/yaml3 v0.0.9 // indirect
github.com/ogen-go/ogen v1.20.3 // indirect
Expand All @@ -120,16 +117,13 @@ require (
github.com/segmentio/asm v1.2.1 // indirect
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/speakeasy-api/jsonpath v0.6.3 // indirect
github.com/speakeasy-api/openapi v1.19.2 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/tinylib/msgp v1.6.4 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.71.0 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/woodsbury/decimal128 v1.4.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
Expand All @@ -145,6 +139,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/mod v0.35.0 // indirect
Expand All @@ -163,7 +158,4 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
)

tool (
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
golang.org/x/vuln/cmd/govulncheck
)
tool golang.org/x/vuln/cmd/govulncheck
102 changes: 0 additions & 102 deletions go.sum

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions modules/compute/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ func (m *Module) PythonAPIDocs() map[string]types.ModuleDoc {
"get_node": {Signature: "get_node(node_id, datasource=None) -> dict", Description: "Get one compute node by id"},
"list_audit": {Signature: "list_audit(datasource=None) -> dict", Description: "List audit-log entries"},
"meta": {Signature: "meta(datasource=None) -> dict", Description: "Get service metadata (version, limits, capabilities)"},
"list_api_operations": {Signature: "list_api_operations(datasource=None) -> dict", Description: "List the operations the compute service currently advertises, with their path/query/body arguments"},
"call": {Signature: "call(operation, datasource=None, **kwargs) -> dict", Description: "Call any compute API operation by name; the interface is discovered from the running service, so operations added upstream work without a panda upgrade"},
},
},
}
Expand Down
22 changes: 22 additions & 0 deletions modules/compute/python/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,3 +671,25 @@ def delete_ssh_key(key_id: str, datasource: str | None = None) -> Any:
"""Delete one of the caller's SSH public keys."""
_require_compute_available()
return _runtime.invoke_json("compute.delete_ssh_key", _args(datasource, id=key_id))


def list_api_operations(datasource: str | None = None) -> Any:
"""List the operations the compute service currently advertises.

Each entry has the operation name plus its path/query arguments and
whether it takes a request body with any required fields.
"""
_require_compute_available()
return _runtime.invoke_json("compute.list_api_operations", _args(datasource))


def call(operation: str, datasource: str | None = None, **kwargs: Any) -> Any:
"""Call any compute API operation by name.

The interface is discovered from the running service, so operations added
upstream work without a panda upgrade; see :func:`list_api_operations`
for the catalog. Path and query arguments are taken by name and everything
else becomes a request-body field. Mutations need an ``idempotency_key``.
"""
_require_compute_available()
return _runtime.invoke_json("compute." + operation, _args(datasource, **kwargs))
80 changes: 80 additions & 0 deletions pkg/cli/compute.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ var (
computeForkPaused bool
computePortProtocol string
computePortService string
computeCallArgs []string
computeCallJSON string
)

var computeCmd = &cobra.Command{
Expand Down Expand Up @@ -223,11 +225,19 @@ func init() {
computeUsersCmd.AddCommand(computeUsersListCmd, computeUsersGetCmd)
computeNodesCmd.AddCommand(computeNodesListCmd, computeNodesGetCmd)

computeCallCmd.Flags().StringArrayVar(&computeCallArgs, "arg", nil,
"Operation argument as key=value; values parse as JSON when possible; repeatable")
computeCallCmd.Flags().StringVar(&computeCallJSON, "json", "",
"Operation arguments as one JSON object")
computeCallCmd.Flags().StringVar(&computeIdempotency, "idempotency-key", "",
"Idempotency key to make a mutation safely retryable (generated per invocation otherwise)")

computeCmd.AddCommand(
computeDatasourcesCmd,
computeMetaCmd,
computeAuditCmd,
computeSessionCmd,
computeCallCmd,
computeSandboxesCmd,
computeImagesCmd,
computeForksCmd,
Expand Down Expand Up @@ -366,6 +376,76 @@ var computeAuditCmd = &cobra.Command{
},
}

var computeCallCmd = &cobra.Command{
Use: "call [operation]",
Short: "Call any compute API operation by name",
Long: `Call any operation the compute service advertises, including ones this CLI
has no dedicated command for. The interface is discovered from the running
service, so new operations work without upgrading panda.

Run without arguments to list the available operations with their arguments.
Pass arguments with --arg key=value; values parse as JSON when possible
(numbers, booleans, arrays, objects) and as plain strings otherwise, and
--json supplies a full argument object in one flag. Path and query arguments
are taken by name; everything else becomes a request-body field.

Mutations require an idempotency key; one is generated per invocation unless
--idempotency-key is set.

Examples:
panda compute call
panda compute call list_sandboxes --arg limit=5
panda compute call get_sandbox --arg id=sb-123
panda compute call snapshot_sandbox --arg id=sb-123 --arg note='before upgrade'
panda compute call expose_port --json '{"id":"sb-123","port":8080}'`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return runComputeRaw(cmd, "compute.list_api_operations", computeArgs())
}

opArgs := computeArgs()

if computeCallJSON != "" {
var decoded map[string]any
if err := json.Unmarshal([]byte(computeCallJSON), &decoded); err != nil {
return fmt.Errorf("--json: %w", err)
}

for key, value := range decoded {
opArgs[key] = value
}
}

for _, entry := range computeCallArgs {
key, raw, found := strings.Cut(entry, "=")
if !found || key == "" {
return fmt.Errorf("--arg %q is not key=value", entry)
}

opArgs[key] = parseComputeCallValue(raw)
}

if _, ok := opArgs["idempotency_key"]; !ok {
opArgs["idempotency_key"] = computeIdemOrGenerated()
}

return runComputeRaw(cmd, "compute."+args[0], opArgs)
},
}

// parseComputeCallValue decodes an --arg value as JSON when possible so
// numbers, booleans, arrays, and objects keep their types, falling back to
// the raw string.
func parseComputeCallValue(raw string) any {
var value any
if err := json.Unmarshal([]byte(raw), &value); err != nil {
return raw
}

return value
}

var computeSessionCmd = &cobra.Command{
Use: "session",
Short: "Show the authenticated session and identity",
Expand Down
5 changes: 0 additions & 5 deletions pkg/compute/codegen.yaml

This file was deleted.

Loading