Skip to content

phctl v0.18.0

Choose a tag to compare

@andreeapid andreeapid released this 19 Aug 08:47
· 14 commits to main since this release

Added

  • phctl kubernetes lb-firewall: list, get, create, update, delete for the firewall in front of a cluster's load balancer. update is a PATCH that sends only the flags you actually pass, so it cannot blank a field you did not mention, and it refuses an empty change rather than making a round trip the API would answer 200 to. Each field it did send is read back out of the response, so a rule the API reports unchanged fails instead of being announced as updated. --direction and --action are validated against the schema's enums before the request, because a typo would otherwise reach a live load balancer as a rejected write.

  • phctl kubernetes cluster update: rename a cluster, set delete protection, or replace its feature set. Changing features confirms first — features the new set omits are uninstalled and their workloads restart. Every setting is read back out of the response: the route answers 200 regardless of whether it applied anything, so a rename or a protection change that did not take now fails instead of reporting success.

    Removing every feature is rejected up front rather than attempted. PatchedClusterDetail.features is generated with omitempty, so an empty list is dropped from the request body and the server would keep the current features while answering 200. A repeated feature is rejected too: the server stores a set, so the response would come back one element shorter than the request and read as an unapplied change.

  • phctl kubernetes cluster upgrade-feature: upgrade a cluster feature (cert-manager and friends) to the latest version compatible with the cluster's Kubernetes release, with --retry for a failed install. It confirms first because the feature's workloads restart, and it checks the reported status rather than the HTTP code — the route answers 200 with a non-OK status when it declines the work.

  • phctl kubernetes cluster toggle-vm-access and cluster eligible-vms: turn cloud VM access to the cluster's private network on or off, and list the VMs that could then be connected. The toggle flips the current setting rather than setting it, so it confirms first and reports the state the cluster ended up in; running it twice returns to where you started.

  • phctl kubernetes cluster kubeconfig --regenerate: issue a fresh kubeconfig. It confirms first, because every copy of the previous one stops working. The command also now rejects an empty or whitespace-only response instead of writing out a file that looks like a kubeconfig but configures nothing — including through --merge.

  • phctl kubernetes pool get and pool resize: pool details with its nodes, and a node-count change. resize confirms because growing a pool provisions billable VMs and shrinking one destroys them, and it requires --size — the API treats a body without new_size as a no-op and still answers 200. The work is asynchronous, so the command reports the size the pool still has rather than claiming the new one.

  • phctl kubernetes node get and node rrd: a single node's details, and its recorded metric series. rrd renders every field the API sends, disk I/O included, and prints the numbers as digits — JSON numbers decode to float64, which %v would have shown as 1.7555e+09 for a Unix timestamp.

  • phctl kubernetes {http,tcp,udp}-route get and update: route details, and a partial update. update is a PATCH that sends only the flags you pass, so an omitted field keeps its current value, and it reads each one back out of the response. It deliberately builds the body from the zero value rather than NewPatched*Route(): that constructor seeds the schema defaults for backend_namespace, path_prefix and enable_tls, which a PATCH would then send as though the caller had asked for them.

  • --backend-namespace on {http,tcp,udp}-route create and update: the backend service's namespace could not be set from the CLI, so a backend outside default was unreachable.

  • phctl kubernetes port-forward: list, get, create, update, delete. A port forward publishes an address inside the cluster on the load balancer's public IP; phctl kubernetes lb-firewall governs what may reach it. update is a PATCH that sends only what you pass and confirms the change landed, --protocol is validated against the schema enum before the request, and delete confirms because traffic reaching the service through it stops.

  • phctl kubernetes node metrics: current CPU, memory, disk and network counters for a node.

  • phctl kubernetes node rrd --timeframe: select the window (hour, day, week, month, year). An unknown value is rejected rather than passed on, because the API silently falls back to hour instead of erroring.

Fixed

  • {http,tcp,udp}-route list works at all. These endpoints paginate, but the commands decoded a bare JSON array, so every call failed against the real API. The schema did not describe the response, and the commands had only structural tests, so nothing caught it. They now page through cmdutil.FetchAll against the generated Paginated*List models.
  • {http,tcp,udp}-route create no longer panics on an empty response body. A 201 with no body decodes to a nil route, which the success message then dereferenced.

Changed

  • Requires sdk-go v0.13.0. Every gap this section previously listed was an API schema defect, now fixed in phclient and regenerated:

    • Port forwards are reachable. All six routes had no request body and no response schema, so the SDK generated POST/PUT methods that send nothing and no model to decode into. ClusterBackendMixin.cluster read self.kwargs["cluster_id"], which drf-spectacular cannot supply, and the KeyError made it abandon the whole viewset. The three Gateway route viewsets lost their GET schemas the same way.
    • node metrics can be decoded. NodeMetricsResponse declared its byte counters as bare IntegerField, which generates as int32; a node with 2 GiB of RAM reports one past that. They are int64 now, and disk/maxdisk are documented — the endpoint always returned them.
    • ClusterDetail carries the types it sends. dual_stack and talos_upgrade_available are booleans, storage_quota_gb and last_pool_used_bytes integers, price_per_hour a number. All five were declared as strings, which made the whole cluster object undecodable — so cluster update could not have worked against a real cluster.
    • The RRD timeframe parameter is declared, so a window other than the default is reachable.

    The regeneration also removed the ...Retrieve2 operations, which existed only because the list and detail reads collided on one operation id while the schema was incomplete. The reads are now ...List and ...Retrieve.