Skip to main content

A Pulumi provider for managing DevZero infrastructure resources.

Project description

pulumi-devzero

The official Python Pulumi provider for DevZero — manage clusters, workload policies, and node policies as code.

PyPI version License: MIT Pulumi Registry


Installation

pip install pulumi-devzero

Requires: pulumi>=3.0.0,<4.0.0, Python 3.9+


Configuration

Before using the DevZero Pulumi provider, configure your credentials using Pulumi config.

1. Generate a Personal Access Token (PAT)

Go to the DevZero user settings page to generate your PAT token:

https://www.devzero.io/settings/user-settings/general

Create a Personal Access Token and copy it.

2. Find your Team ID

You can find your DevZero Team ID in the organization settings:

https://www.devzero.io/settings/organization-settings/account

Copy the Team ID value from this page.

3. Set Pulumi configuration

Run the following commands in your Pulumi project:

pulumi config set --secret devzero:token <YOUR_PAT_TOKEN>
pulumi config set devzero:teamId <TEAM_ID>
pulumi config set devzero:url https://dakr.devzero.io  # optional, this is the default

Example

pulumi config set --secret devzero:token dz_pat_xxxxxxxxxxxxx
pulumi config set devzero:teamId team_123456789

The --secret flag ensures that your token is encrypted in the Pulumi state.


Quick Start

import pulumi
import pulumi_devzero as devzero

# 1. Create a cluster
cluster = devzero.resources.Cluster("prod-cluster",
    name="prod-cluster",
)

# 2. Create a workload policy with CPU vertical scaling
policy = devzero.resources.WorkloadPolicy("cpu-scaling-policy",
    name="cpu-scaling-policy",
    description="Policy with CPU vertical scaling enabled",
    cpu_vertical_scaling=devzero.resources.VerticalScalingArgsArgs(
        enabled=True,
        target_percentile=0.95,
        min_request=50,
        max_request=4000,
        max_scale_up_percent=100,
        max_scale_down_percent=25,
        overhead_multiplier=1.1,
        limits_adjustment_enabled=True,
        limit_multiplier=1.5,
    ),
)

# 3. Apply the policy to the cluster for all Deployments
target = devzero.resources.WorkloadPolicyTarget("prod-cluster-target",
    name="prod-cluster-deployments-target",
    description="Apply cpu-scaling-policy to all Deployments in prod-cluster",
    policy_id=policy.id,
    cluster_ids=[cluster.id],
    kind_filter=["Deployment"],
    enabled=True,
)

pulumi.export("cluster_id", cluster.id)
pulumi.export("cluster_token", pulumi.Output.secret(cluster.token))
pulumi.export("policy_id", policy.id)
pulumi.export("target_id", target.id)
pulumi up

Resources

Cluster

Provision and manage a DevZero cluster.

import pulumi
import pulumi_devzero as devzero

cluster = devzero.resources.Cluster("my-cluster",
    name="my-cluster",
)

pulumi.export("id", cluster.id)
pulumi.export("token", pulumi.Output.secret(cluster.token))

WorkloadPolicy

Configure vertical and horizontal scaling policies for workloads.

import pulumi_devzero as devzero

policy = devzero.resources.WorkloadPolicy("my-policy",
    name="my-policy",
    description="Vertical scaling for CPU and memory",
    enable_pmax_protection=True,
    pmax_ratio_threshold=3.0,
    cpu_vertical_scaling=devzero.resources.VerticalScalingArgsArgs(
        enabled=True,
        target_percentile=0.95,
        min_request=50,
        max_request=4000,
        max_scale_up_percent=100,
        max_scale_down_percent=25,
        overhead_multiplier=1.1,
        limits_adjustment_enabled=True,
        limit_multiplier=1.5,
        adjust_req_even_if_not_set=True,
        limits_removal_enabled=False,
    ),
    memory_vertical_scaling=devzero.resources.VerticalScalingArgsArgs(
        enabled=True,
        target_percentile=0.9,
        min_request=128,
        max_request=8192,
        max_scale_up_percent=50,
        max_scale_down_percent=20,
        overhead_multiplier=1.2,
        limits_adjustment_enabled=True,
        limit_multiplier=1.3,
        adjust_req_even_if_not_set=True,
        limits_removal_enabled=False,
    ),
)

VerticalScalingArgsArgs fields:

Field Type Description
enabled bool Enable this scaling axis
target_percentile float Percentile of observed usage to target (e.g. 0.95)
min_request int Minimum resource request (millicores / MiB)
max_request int Maximum resource request (millicores / MiB)
max_scale_up_percent float Max % to scale up in one step. Default: 1000
max_scale_down_percent float Max % to scale down in one step. Default: 1.0
overhead_multiplier float Multiplier added on top of the recommendation
limits_adjustment_enabled bool Whether to also adjust resource limits
limit_multiplier float Limits = request × limit_multiplier
min_data_points int Minimum data points before a recommendation is emitted. Default: 20
adjust_req_even_if_not_set bool Recommend requests even when the workload has no existing requests set. Default: false
limits_removal_enabled bool Actively remove limits from workloads (CPU axis only — memory limits removal is not supported). Takes precedence over limits_adjustment_enabled. Default: false

WorkloadPolicy pmax & VPA knob fields:

Field Type Description
enable_pmax_protection bool Raise requests to cover peak usage when max/recommendation ratio exceeds pmax_ratio_threshold. Default: false
pmax_ratio_threshold float Max-to-recommendation ratio that triggers pmax protection. Default: 3.0
loopback_period_seconds int Look-back period in seconds for usage data. Default: 86400 (24 h)
min_data_points int Global minimum data points for recommendations. Default: 15
min_change_percent float Global minimum change threshold. Default: 0.2 (20%)
min_vpa_window_data_points int Minimum data points in VPA analysis window. Default: 30
cooldown_minutes int Minutes between applying recommendations. Default: 300 (5 h)

WorkloadPolicyTarget

Apply a workload policy to one or more clusters with optional filters.

import pulumi_devzero as devzero

target = devzero.resources.WorkloadPolicyTarget("my-target",
    name="my-target",
    policy_id=policy.id,
    cluster_ids=[cluster.id],
    kind_filter=["Deployment", "StatefulSet"],
    namespace_selector=devzero.resources.LabelSelectorArgsArgs(match_labels={"env": "production"}),
    enabled=True,
)

Fields:

Field Type Description
name str Unique target name
policy_id str ID of the WorkloadPolicy to apply
cluster_ids list[str] Cluster IDs to target
description str Human-readable description (optional)
priority int Evaluation priority; higher value wins when targets overlap
kind_filter list[str] Pod | Deployment | StatefulSet | DaemonSet | Job | CronJob | ReplicaSet | ReplicationController | Rollout
workload_names list[str] Explicit list of workload names to include
node_group_names list[str] Restrict matching to specific node groups by name
name_pattern NamePatternArgsArgs Regex pattern to match workload names
namespace_selector LabelSelectorArgsArgs Select namespaces by labels (match_labels / match_expressions)
workload_selector LabelSelectorArgsArgs Select workloads by labels
enabled bool Activate the target

NodePolicy

Configure node provisioning and pooling (AWS / Azure) using Karpenter under the hood.

import pulumi_devzero as devzero

node_policy = devzero.resources.NodePolicy("my-node-policy",
    name="my-node-policy",
    description="AWS node policy with on-demand and spot capacity",
    weight=10,
    capacity_types=devzero.resources.LabelSelectorArgsArgs(match_expressions=[devzero.resources.LabelSelectorRequirementArgsArgs(key="<label-key>", operator="In", values=["<value>"])]),
    instance_categories=devzero.resources.LabelSelectorArgsArgs(match_labels={"<label-key>": "<label-value>"}),
    labels={"environment": "production"},
    taints=[devzero.resources.TaintArgsArgs(key="dedicated", value="gpu", effect="NoSchedule")],
    disruption=devzero.resources.DisruptionPolicyArgsArgs(
        consolidation_policy="WhenEmptyOrUnderutilized",
        consolidate_after="30s",
        expire_after="720h",
    ),
    limits=devzero.resources.ResourceLimitsArgsArgs(cpu="1000", memory="1000Gi"),
    aws=devzero.resources.AWSNodeClassSpecArgsArgs(
        ami_family="AL2",
        role="KarpenterNodeRole",
        subnet_selector_terms=[devzero.resources.SubnetSelectorTermArgsArgs(tags={"karpenter.sh/discovery": "my-cluster"})],
        security_group_selector_terms=[devzero.resources.SecurityGroupSelectorTermArgsArgs(tags={"karpenter.sh/discovery": "my-cluster"})],
        block_device_mappings=[devzero.resources.BlockDeviceMappingArgsArgs(
            device_name="/dev/xvda",
            root_volume=True,
            ebs=devzero.resources.BlockDeviceArgsArgs(volume_size="100Gi", volume_type="gp3", encrypted=True),
        )],
    ),
)

NodePolicyArgs fields:

Field Type Description
name str Unique policy name
description str Human-readable description
weight int Priority weight when multiple policies match (higher = preferred)
instance_categories LabelSelectorArgsArgs Filter by instance category letter: e.g. m, c, r (AWS) or D, E (Azure)
instance_families LabelSelectorArgsArgs Filter instance families (e.g. c5, m5)
instance_cpus LabelSelectorArgsArgs Filter by vCPU count
instance_sizes LabelSelectorArgsArgs Filter instance sizes (e.g. large, xlarge)
instance_types LabelSelectorArgsArgs Explicit instance types (e.g. m5.xlarge)
instance_generations LabelSelectorArgsArgs Filter by instance generation
instance_hypervisors LabelSelectorArgsArgs Filter by hypervisor type
zones LabelSelectorArgsArgs Availability zones to provision into
architectures LabelSelectorArgsArgs CPU architectures (e.g. amd64, arm64)
capacity_types LabelSelectorArgsArgs Capacity types: on-demand | spot | reserved
operating_systems LabelSelectorArgsArgs OS filter (e.g. linux, windows)
labels dict[str, str] Labels applied to provisioned nodes
taints list[TaintArgsArgs] Taints applied to provisioned nodes
disruption DisruptionPolicyArgsArgs Node disruption / consolidation settings
limits ResourceLimitsArgsArgs Max total CPU/memory this policy may provision
node_pool_name str Override the Karpenter NodePool name
node_class_name str Override the Karpenter NodeClass name
aws AWSNodeClassSpecArgsArgs AWS-specific node class configuration
azure AzureNodeClassSpecArgsArgs Azure-specific node class configuration
raw list[RawKarpenterSpecArgsArgs] Raw Karpenter YAML (escape hatch)

RawKarpenterSpecArgsArgs fields:

Field Type Description
nodepool_yaml str Raw YAML for a complete Karpenter NodePool resource
nodeclass_yaml str Raw YAML for a complete Karpenter NodeClass resource

DisruptionPolicyArgsArgs fields:

Field Type Description
consolidation_policy str WhenEmpty | WhenEmptyOrUnderutilized
consolidate_after str Wait time after node is empty before consolidating (e.g. 30s)
expire_after str Force-replace nodes after this duration (e.g. 720h)
ttl_seconds_after_empty int Seconds before an empty node is terminated (deprecated; prefer consolidate_after)
termination_grace_period_seconds int Grace period before forcefully terminating a draining node
budgets list[DisruptionBudgetArgsArgs] Limits on how many nodes may be disrupted at once

AWSNodeClassSpecArgsArgs fields:

Field Type Description
ami_family str AMI family: AL2, AL2023, Bottlerocket, Windows2019, Windows2022
role str IAM role name for nodes (Karpenter creates the instance profile)
instance_profile str IAM instance profile name (alternative to role)
subnet_selector_terms list[SubnetSelectorTermArgsArgs] Subnet selectors (by tag or ID)
security_group_selector_terms list[SecurityGroupSelectorTermArgsArgs] Security group selectors
capacity_reservation_selector_terms list[CapacityReservationSelectorTermArgsArgs] EC2 capacity reservation selectors
ami_selector_terms list[AMISelectorTermArgsArgs] AMI selectors (by alias, tag, or ID)
block_device_mappings list[BlockDeviceMappingArgsArgs] EBS volume configuration
instance_store_policy str NVMe instance store policy. Value: INSTANCE_STORE_POLICY_RAID0
tags dict[str, str] AWS tags on all provisioned resources
associate_public_ip_address bool Assign a public IP to nodes
detailed_monitoring bool Enable CloudWatch detailed monitoring
metadata_options MetadataOptionsArgsArgs EC2 IMDS options (IMDSv2, hop limit, etc.)
kubelet KubeletConfigurationArgsArgs Kubelet overrides (max_pods, eviction thresholds, etc.)
user_data str Custom launch template user data
context str Additional EC2 launch template context ARN for advanced customization

AzureNodeClassSpecArgsArgs fields:

Field Type Description
vnet_subnet_id str Azure VNet subnet resource ID
image_family str Image family: AzureLinux, Ubuntu2204, etc.
os_disk_size_gb int OS disk size in GB
fips_mode str Enabled | Disabled
max_pods int Max pods per node
tags dict[str, str] Azure tags on provisioned resources
kubelet AzureKubeletConfigurationArgsArgs Kubelet overrides for Azure nodes

NodePolicyTarget

Apply a node policy to one or more clusters.

import pulumi_devzero as devzero

node_policy_target = devzero.resources.NodePolicyTarget("my-node-policy-target",
    name="my-node-policy-target",
    policy_id=node_policy.id,
    cluster_ids=[cluster.id],
    enabled=True,
)

Fields:

Field Type Description
name str Unique target name
policy_id str ID of the NodePolicy to apply
cluster_ids list[str] Cluster IDs to target. At most 1 entry — the backend rejects more than one.
description str Human-readable description (optional)
enabled bool Activate the target

Note: pulumi destroy removes this resource from Pulumi state but does not delete it on the DevZero backend — no delete RPC exists for NodePolicyTarget.


Data Sources

get_cluster_id_by_name

Look up an existing cluster by name and return its ID. Use this when a cluster was registered manually (not created by Pulumi) and you need its ID to attach policies or inject into values.yaml / a Kubernetes secret.

import pulumi
import pulumi_devzero as devzero

existing = devzero.resources.get_cluster_id_by_name(
    name="my-existing-cluster",
    # team_id is optional — defaults to devzero:teamId from provider config
    # region="us-east-1",        # optional: filter by region
    # cloud_provider="AWS",      # optional: AWS | GCP | AKS | OCI
    # liveness="PREFER_LIVE",    # optional: IGNORE | PREFER_LIVE | REQUIRE_LIVE
)

# Attach a policy to the existing cluster
target = devzero.resources.WorkloadPolicyTarget("my-target",
    name="my-target",
    policy_id=policy.id,
    cluster_ids=[existing.cluster_id],
    kind_filter=["Deployment"],
    enabled=True,
)

pulumi.export("existing_cluster_id", existing.cluster_id)

Inputs:

Field Type Required Description
name str yes Cluster name to look up
team_id str no Defaults to devzero:teamId from provider config
region str no Filter by region name (e.g. us-east-1)
cloud_provider str no Filter by cloud provider: AWS | GCP | AKS | OCI
liveness str no IGNORE (default) | PREFER_LIVE | REQUIRE_LIVE

Outputs:

Field Type Description
cluster_id str UUID of the matching cluster

Note: If multiple clusters share the same name, the newest one is returned by default. Use liveness="PREFER_LIVE" or "REQUIRE_LIVE" to filter by heartbeat freshness.


Destroying Resources

# Tear down all resources in the stack
pulumi destroy

# Remove the stack itself
pulumi stack rm <stack-name>

Links


License

MIT — Copyright (c) 2026 DevZero Inc.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pulumi_devzero-0.1.11.tar.gz (55.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pulumi_devzero-0.1.11-py3-none-any.whl (59.1 kB view details)

Uploaded Python 3

File details

Details for the file pulumi_devzero-0.1.11.tar.gz.

File metadata

  • Download URL: pulumi_devzero-0.1.11.tar.gz
  • Upload date:
  • Size: 55.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for pulumi_devzero-0.1.11.tar.gz
Algorithm Hash digest
SHA256 ef09ace6777212a36900de08960ecc5a192c865fb04641ca45af882995561d4d
MD5 3701abf785a48b1e4584ef9b7d3f97ab
BLAKE2b-256 a05f7a531d877da43e5a1be281a403262d03966b7f9430c5a44d932bae53e19c

See more details on using hashes here.

File details

Details for the file pulumi_devzero-0.1.11-py3-none-any.whl.

File metadata

File hashes

Hashes for pulumi_devzero-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 968367a0428a6c117ed1700dd1cea8813fe4928274df00d1b058994234bb9935
MD5 046684ac0d1894c6cf998e9cf156f54b
BLAKE2b-256 7de6c6f7ec5148d2317203d231714d98c170d29f8b0a50f7880211532b9a62d6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page