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
10 changes: 10 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
- 'go.mod'
- 'go.sum'
- 'Makefile'
- 'tests/smoke/**'
scripts:
- 'scripts/**'
workflow:
Expand Down Expand Up @@ -131,12 +132,21 @@ jobs:
- name: Get dependencies
run: go mod download

- name: Install jq
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update && sudo apt-get install -y jq

- name: Run go vet
run: go vet ./...

- name: Run tests
run: go test -v ./...

- name: Test smoke ownership checks
if: matrix.os == 'ubuntu-latest'
shell: bash
run: bash tests/smoke/cases_test.sh

- name: Run tests (race detector)
run: go test -race ./...

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
ZCP_SMOKE_REGION: ${{ vars.ZCP_SMOKE_REGION }}
ZCP_SMOKE_PROJECT: ${{ vars.ZCP_SMOKE_PROJECT }}
ZCP_SMOKE_CLOUD_PROVIDER: ${{ vars.ZCP_SMOKE_CLOUD_PROVIDER }}
ZCP_SMOKE_ROOT_DISK_SIZE: ${{ vars.ZCP_SMOKE_ROOT_DISK_SIZE }}
run: |
if [ "${{ needs.preflight.outputs.services }}" = "all" ]; then
ARGS=(--bin ./bin/zcp)
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,38 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), using

## [Unreleased]

## [v1.0.0] - 2026-10-11

### Added

- **Safe VM backup restore.** `zcp vm-backup restore <vm-slug> <backup-slug>` verifies that the VM is stopped and that the selected backup is ready, belongs to that VM, and is in the selected region and project before it requests a restore. The command does not stop the VM automatically. It reports when the restore request is accepted, not when the restore is complete.
- **Kubernetes create uses separate control-plane, worker, and root-volume plans.** `zcp kubernetes create` now requires `--control-plane-plan`, `--worker-plan`, and `--storage-plan`, alongside `--storage-category`. The command sends the ZCP API `master_plan`, `worker_plan`, and `blockstorage_plan` fields instead of a single cluster plan. The root-volume plan applies to every node. Under the platform's resource-based model, the cluster object is not charged; charges for nodes, root volumes, and enabled network resources are determined by the platform. Use `--enable-csi` to request Cloud Storage Integration for a supported cluster. `zcp kubernetes get` now shows resource totals and configuration. `zcp kubernetes scale` submits autoscaling settings with minimum and maximum worker counts, or disables autoscaling with a fixed worker count. See the known limitations below.
- **Scheduler-backed VM backup policies.** `zcp vm-backup schedule` creates, lists, reads, updates, pauses, resumes, runs, and deletes VM backup policies. Policies support hourly, daily, weekly, and monthly intervals, IANA timezones, retention counts, names, and descriptions. Weekly policies select a weekday; monthly policies select a day of the month. Policies can request an immediate first backup.
- **`everyOtherDay` policy warning.** The command exposes the API's `everyOtherDay` value. The current platform returns an error after persisting that policy, so the command directs users to list policies before retrying.

### Fixed

- Kubernetes output now shows `-` for high availability when the API does not report its state.
- The client now escapes VM backup schedule IDs in API paths. Schedule identifiers containing reserved URL characters now reach the intended scheduler action route.
- **`vm-backup create` now reports the created schedule slug.** It prints the created schedule in table output and emits valid JSON or YAML for structured output. When the create endpoint returns only an acknowledgement, the command identifies the new schedule from a scoped pre-create snapshot and bounded read-only lookup. It never repeats an accepted create request. If the command cannot identify the schedule, the error tells you to list it before creating another one. _Fixes #76._
- **`kubernetes delete` now submits an immediate service-cancellation request.** The command reads the cluster first, uses its reported billing cycle when available, and reports that deletion was requested rather than completed.
- **Service-cancellation commands now reject API error envelopes.** A cancellation response with an API status other than `Success`, including one returned with HTTP 200, now returns the server error instead of reporting the request as accepted.
- **Instance and Kubernetes deletion commands now check the current lifecycle state before sending a cancellation request.** Both refuse deletion when the current state is unavailable or Starting. Kubernetes deletion also refuses a Destroying state, while still allowing failed clusters to be cleaned up.
- **DNS listings now retrieve every reported page.** `dns.Service.List` returns an error rather than a partial domain list if a later page fails or pagination metadata is inconsistent.
- **`dns show` now resolves an omitted status from the matching domain in `dns list`.** It stops reading pages as soon as it finds that domain. An explicit status in the detail response is preserved. If the matching list entry also lacks status, output remains `-`. If the list lookup fails, the command returns an error. _Follow-up to #69._

### Changed

- **Instance and Kubernetes creation now select root storage separately.** `zcp instance create` requires a named `--plan`, `--blockstorage-plan`, and `--root-disk-size`. `zcp kubernetes create` requires `--control-plane-plan`, `--worker-plan`, `--storage-plan`, and `--root-disk-size`. The root storage tier and capacity are sent separately from fixed compute plans. `zcp kubernetes get` lists each root volume's reported capacity separately from compute-plan storage. The retired instance `--cpu`, `--memory`, and `--disk` flags no longer select custom compute. Use `zcp plan vm` to choose a plan; its output includes `TAG`.

### Known limitations

- **Automatic Kubernetes scale-out failed in staging.** `zcp kubernetes scale --enable-autoscaling` submitted the requested autoscaling configuration, but no worker was added. Staging scaling tests also recreated existing node root-volume subscriptions. Billing correctness after scaling remains unverified; this release does not resolve that platform issue. Manual worker scaling was tested separately.
- **`everyOtherDay` policy creation can persist before failing.** List VM backup schedules after an error and remove any unintended policy before retrying.
- **Kubernetes create/delete and VM backup restore responses are acceptance-only.** They confirm that the platform accepted the request, not that the operation completed. Check the resource's current status and, after a restore, its activity logs.

## [v0.0.31] - 2026-10-09

### Security

- **Go toolchain `1.26.8` -> `1.26.9` and `golang.org/x/net` `v0.58.0` -> `v0.60.0`.** Resolves the reachable standard-library and `x/net` vulnerabilities reported by `govulncheck`.
Expand Down
162 changes: 126 additions & 36 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,142 @@
# zcp v0.0.31 Release Notes
# zcp v1.0.0 Release Notes

v0.0.31 fixes ACL rule listings that stopped at the first API page, adds
bounded ACL rule listing controls, and includes security updates to the Go
toolchain and networking dependencies.
v1.0.0 requires separate compute and root-storage selections for new instances
and Kubernetes clusters. It adds VM backup schedule commands, restore
preflight checks, lifecycle-state checks for deletion, and complete DNS lists.

Replace every quoted placeholder in the examples with a value from your account.

## Highlights

**List every rule in an ACL.** `zcp acl rules` now retrieves every API page, so
ACLs with more than the default page size return their complete rule set.
### Choose compute and root storage separately

New instances use a named compute plan, a named root-storage plan, and an
explicit root-disk capacity. Kubernetes clusters use distinct control-plane,
worker, and root-storage plans. This makes the resources selected for compute
and root storage explicit in the request.

```bash
zcp acl rules <vpc-slug> <acl-name-or-id>
zcp plan vm --region yul-1
zcp plan storage --region yul-1

zcp instance create \
--name my-vm \
--template ubuntu-2604-lts-1 \
--plan "<compute-plan>" \
--blockstorage-plan "<root-storage-plan>" \
--root-disk-size 100 \
--network-plan "<network-plan>" \
--storage-category "<storage-category>" \
--billing-cycle hourly \
--region yul-1 \
--project default-9
```

**Safer API pagination.** If a later page fails or reports inconsistent
pagination metadata, the command returns an error instead of a partial rule
list. A response that explicitly reports `total: 0` must contain no rules.
Kubernetes creation now selects each node role and the root volume separately.
The root-storage selection and capacity apply to every cluster node.

```bash
zcp kubernetes create \
--name my-cluster \
--version "<kubernetes-version>" \
--control-plane-plan "<control-plane-plan>" \
--worker-plan "<worker-plan>" \
--storage-plan "<root-storage-plan>" \
--root-disk-size 100 \
--storage-category "<storage-category>" \
--workers 3 \
--billing-cycle hourly \
--region yul-1 \
--project default-9 \
--ssh-key "<ssh-key>"
```

**Choose how many ACL rules to return.** Use `--max-items` for a bounded
result, `--starting-token` to resume it, `--page-size` to set the API request
size, or `--no-paginate` to request one API page. Bounded and single-page JSON
and YAML output use an object with a `rules` array and optional `next_token`.
Table output prints the continuation token on standard error.
`zcp kubernetes get` now displays reported node resources, root volumes,
network details, and autoscaling status when the API provides them. Use
`--enable-csi` on create to request Cloud Storage Integration for a supported
cluster.

### Manage VM backup schedules

`zcp vm-backup schedule` can create, list, get, update, pause, resume, run-now,
and delete VM backup schedules. It supports hourly, daily, weekly, and monthly
intervals, IANA timezones, retention counts, and an optional immediate backup.

```bash
zcp acl rules <vpc-slug> <acl-name-or-id> --max-items 25 --output json
zcp acl rules <vpc-slug> <acl-name-or-id> --max-items 25 --starting-token '<next_token>' --output json
zcp acl rules <vpc-slug> <acl-name-or-id> --no-paginate --output yaml
zcp vm-backup schedule create my-vm \
--name nightly \
--interval dailyAt \
--at 01:00 \
--timezone America/Toronto \
--retention 7 \
--immediate

zcp vm-backup schedule list
zcp vm-backup schedule pause "<schedule-id>"
zcp vm-backup schedule run-now "<schedule-id>"
```

`--no-paginate` cannot be combined with the other pagination flags. A
continuation token applies only to the same ACL and retains its page size.
`zcp vm-backup restore <vm-slug> <backup-slug>` overwrites the VM's current
disks. It verifies that the VM is stopped and the backup is ready, belongs to
that VM, and is in the selected region and project before submitting the restore
request. It prompts for confirmation by default; use `--yes` to skip the prompt
when scripting an intentional restore:

**Security updates.** The selected Go toolchain is now Go 1.26.9 and
`golang.org/x/net` is now v0.60.0. These updates resolve the reachable
standard-library and networking vulnerabilities reported by `govulncheck`.
```bash
zcp vm-backup restore "<vm-slug>" "<backup-slug>" --yes
```

## Go library consumers
`zcp vm-backup create` also returns the created schedule slug in table, JSON,
and YAML output.

### Safer lifecycle and DNS behavior

- Instance and Kubernetes deletion commands check the current lifecycle state before
requesting immediate cancellation. API error envelopes are reported even when
returned with HTTP 200.
- `zcp dns list` retrieves every reported page and fails rather than returning a
partial list if a later page fails or its pagination metadata is inconsistent.
- `zcp dns show` uses the matching list entry when the detail response omits a
domain status. It shows `-` only when the API reports no status.

## Breaking changes and migration

`acl.Service.ListRules` now returns rules from every page. Callers receive an
error and no partial rule list when a later page cannot be retrieved or its
pagination metadata is inconsistent. Terraform provider maintainers must adopt
this `zcp-cli` module release to receive this behavior.
`zcp instance create` no longer accepts `--cpu`, `--memory`, or `--disk` to
select a custom compute plan. Choose a named compute plan with `zcp plan vm`.
Every new instance must also pass both `--blockstorage-plan` and
`--root-disk-size`.

`zcp kubernetes create` now requires `--control-plane-plan`, `--worker-plan`,
`--storage-plan`, and `--root-disk-size`. Replace a former single cluster-plan
selection with plans for both node roles and the shared root-storage tier.

The root-storage plan must be a named available tier. A custom root-storage
plan is not supported by these commands.

## Go library consumers

---
The Go module adds scheduler-backed VM backup APIs, VM backup restore support,
DNS `FindBySlug`, richer Kubernetes response types, and root-storage fields on
instance and Kubernetes create requests. No exported request fields were
removed. DNS list callers now receive an error rather than a partial result when
pagination fails. Consumers that construct instance or Kubernetes create
requests should populate the separate root-storage fields before moving to this
release.

## Known limitations

- Automatic Kubernetes scale-out failed in staging. `zcp kubernetes scale --enable-autoscaling` submitted the requested autoscaling configuration, but no worker was added. Staging scaling tests also recreated existing node root-volume subscriptions. Billing correctness after scaling remains unverified; this release does not resolve that platform issue. Manual worker scaling was tested separately.
- The current platform can persist an `everyOtherDay` VM backup policy before
returning an error. List schedules after an error and remove any unintended
policy before retrying.
- Kubernetes create/delete and VM backup restore operations run asynchronously.
A successful command confirms acceptance of the request, not completion of
the operation. Check the resource's current status and, after a restore, its
activity logs.

## Installation and upgrade

The install script installs the latest release and upgrades an existing
The install scripts install the latest release and upgrade an existing
installation in place.

**Linux / macOS**
Expand All @@ -62,19 +151,20 @@ curl -fsSL https://github.com/zsoftly/zcp-cli/releases/latest/download/install.s
irm https://github.com/zsoftly/zcp-cli/releases/latest/download/install.ps1 | iex
```

**Manual download:** grab your platform's binary from the
[Releases](https://github.com/zsoftly/zcp-cli/releases) page, `chmod +x`, and
place it on your `PATH`.
**Manual download:** download the binary or archive for your platform from the
[Releases](https://github.com/zsoftly/zcp-cli/releases) page. Extract an archive
first. Rename the platform binary to `zcp` (or `zcp.exe` on Windows). On Linux
or macOS, run `chmod +x zcp`, then place it on your `PATH`.

**Verify:**

```bash
zcp version # zcp version v0.0.31
zcp version # zcp version v1.0.0
```

First-time setup after installing:
First-time setup:

```bash
zcp profile add default --region yul-1 --project default-9 # prompts for bearer token
zcp profile add default --region yul-1 --project default-9
zcp auth validate
```
2 changes: 1 addition & 1 deletion cmd/zcp/root/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ profiles:

rootCmd.SetOut(&bytes.Buffer{})
rootCmd.SetErr(&bytes.Buffer{})
rootCmd.SetArgs([]string{"instance", "create", "--name", "test-vm"})
rootCmd.SetArgs([]string{"instance", "create", "--name", "test-vm", "--plan", "ca2sxs"})

err := rootCmd.Execute()
if err == nil {
Expand Down
Loading
Loading