NewCompare CPU & GPU pricing across AWS, Azure & GCP
Pulumi

Importing Resources

Bring existing DevZero resources under Pulumi management without recreating them.

Importing Existing Resources

If a Cluster, WorkloadPolicy, WorkloadPolicyTarget, WorkloadRule, NodePolicy, or NodePolicyTarget already exists in DevZero, you can bring it under Pulumi management instead of recreating it. Write the resource block as you normally would, attach the existing resource's ID via the import option, and Pulumi adopts it into state.

Step-by-step

  1. Get the resource ID from the DevZero UI:
    • Cluster — Dashboard
    • Workload policy / target — Optimization → Policies → Workload
    • Node policy / target — Optimization → Policies → Node
    • Workload rule — Go to Dashboard → Clusters → [your cluster] → Workload Analysis (ensure the MPA v2 toggle is enabled), then select the rule to view its ID.
    • Export as IaC shortcut — On any resource row, click the ⋮ (three-dot) menu and select Export as IaC. This generates a ready-to-use resource block with all live values pre-filled — paste it directly into your code as a starting point for the next step.
  2. Write the resource block, filling in as many fields as you know, and attach the ID using the import option (syntax below).
  3. Run pulumi preview --diff. This shows exactly which fields in your code don't match the live resource, with full before/after values.
  4. Update your code to match the live values shown in the diff, and re-run pulumi preview --diff until it shows a clean import with no changes.
  5. Run pulumi up to adopt the resource.
  6. Remove the import option from the code — it's only needed for this one-time step.

Don't run pulumi up while pulumi preview still shows changes alongside the import. That means your code doesn't fully match the live resource yet, and applying it will overwrite the live configuration to match your code — not just adopt it as-is.

Example for clusters

import * as pulumi from "@pulumi/pulumi";
import { resources } from "@devzero/pulumi-devzero";

const cluster = new resources.Cluster("prod-cluster", {
    name: "prod-cluster",
}, { import: "cluster-abc123" });

export const clusterId = cluster.id;
import pulumi
from pulumi_devzero.resources import Cluster, ClusterArgs

cluster = Cluster(
    "prod-cluster",
    args=ClusterArgs(name="prod-cluster"),
    opts=pulumi.ResourceOptions(import_="cluster-abc123"),
)

pulumi.export("cluster_id", cluster.id)
package main

import (
    "github.com/devzero-inc/pulumi-provider-devzero/sdk/go/devzero/resources"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {
        cluster, err := resources.NewCluster(ctx, "prod-cluster", &resources.ClusterArgs{
            Name: pulumi.String("prod-cluster"),
        }, pulumi.Import(pulumi.ID("cluster-abc123")))
        if err != nil {
            return err
        }

        ctx.Export("clusterId", cluster.ID())
        return nil
    })
}

Example — workload policy and target together

Importing a WorkloadPolicy alongside a WorkloadPolicyTarget that references it. Note that the target's policyId points at policy.id rather than hardcoding the policy's ID a second time:

import * as pulumi from "@pulumi/pulumi";
import { resources } from "@devzero/pulumi-devzero";

const policy = new resources.WorkloadPolicy("aggressive-binpacking", {
    name: "Aggressive binpacking",
    cpuVerticalScaling: {
        enabled: true,
        minRequest: 20,
    },
    memoryVerticalScaling: {
        enabled: true,
        minRequest: 10485760,
    },
    loopbackPeriodSeconds: 604800,
    actionTriggers: ["on_schedule"],
    cronSchedule: "*/25 * * * *",
}, { import: "policy-abc123" });

const target = new resources.WorkloadPolicyTarget("test-spark", {
    name: "test spark",
    policyId: policy.id,
    enabled: true,
    priority: 0,
    clusterIds: ["cluster-abc123"],
    kindFilter: ["ScheduledSparkApplication"],
}, { import: "target-abc123" });

export const policyId = policy.id;
import pulumi
from pulumi_devzero.resources import (
    WorkloadPolicy, WorkloadPolicyArgs,
    WorkloadPolicyTarget, WorkloadPolicyTargetArgs,
)
from pulumi_devzero.resources.types import VerticalScalingArgs

policy = WorkloadPolicy(
    "aggressive-binpacking",
    args=WorkloadPolicyArgs(
        name="Aggressive binpacking",
        cpu_vertical_scaling=VerticalScalingArgs(
            enabled=True,
            min_request=20,
        ),
        memory_vertical_scaling=VerticalScalingArgs(
            enabled=True,
            min_request=10485760,
        ),
        loopback_period_seconds=604800,
        action_triggers=["on_schedule"],
        cron_schedule="*/25 * * * *",
    ),
    opts=pulumi.ResourceOptions(import_="policy-abc123"),
)

target = WorkloadPolicyTarget(
    "test-spark",
    args=WorkloadPolicyTargetArgs(
        name="test spark",
        policy_id=policy.id,
        enabled=True,
        priority=0,
        cluster_ids=["cluster-abc123"],
        kind_filter=["ScheduledSparkApplication"],
    ),
    opts=pulumi.ResourceOptions(import_="target-abc123"),
)

pulumi.export("policy_id", policy.id)
package main

import (
    "github.com/devzero-inc/pulumi-provider-devzero/sdk/go/devzero/resources"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {
        policy, err := resources.NewWorkloadPolicy(ctx, "aggressive-binpacking", &resources.WorkloadPolicyArgs{
            Name: pulumi.String("Aggressive binpacking"),
            CpuVerticalScaling: &resources.VerticalScalingArgs{
                Enabled:    pulumi.Bool(true),
                MinRequest: pulumi.Int(20),
            },
            MemoryVerticalScaling: &resources.VerticalScalingArgs{
                Enabled:    pulumi.Bool(true),
                MinRequest: pulumi.Int(10485760),
            },
            LoopbackPeriodSeconds: pulumi.Int(604800),
            ActionTriggers:        pulumi.StringArray{pulumi.String("on_schedule")},
            CronSchedule:          pulumi.String("*/25 * * * *"),
        }, pulumi.Import(pulumi.ID("policy-abc123")))
        if err != nil {
            return err
        }

        _, err = resources.NewWorkloadPolicyTarget(ctx, "test-spark", &resources.WorkloadPolicyTargetArgs{
            Name:       pulumi.String("test spark"),
            PolicyId:   policy.ID(),
            Enabled:    pulumi.Bool(true),
            Priority:   pulumi.Int(0),
            ClusterIds: pulumi.StringArray{pulumi.String("cluster-abc123")},
            KindFilter: pulumi.StringArray{pulumi.String("ScheduledSparkApplication")},
        }, pulumi.Import(pulumi.ID("target-abc123")))
        if err != nil {
            return err
        }

        ctx.Export("policyId", policy.ID())
        return nil
    })
}

Example — WorkloadRule

WorkloadRule pins rules to a single workload (kind/namespace/name on a cluster), so its nested cpuRule/memoryRule/hpaRule/emergencyResponse blocks tend to carry the most fields to reconcile during import:

import * as pulumi from "@pulumi/pulumi";
import { resources } from "@devzero/pulumi-devzero";

const rule = new resources.WorkloadRule("controller-manager-rule", {
    clusterId: "cluster-abc123",
    namespace: "devzero-system",
    kind: "Deployment",
    name: "controller-manager",
    autoGenerate: false,
    cpuRule: {
        enabled: true,
        minRequest: 10,
        maxRequest: 32000,
        limitMultiplier: 1,
        limitsRemovalEnabled: true,
        targetPercentile: 0.85,
    },
    memoryRule: {
        enabled: true,
        minRequest: 67108864,
        maxRequest: 68719476736,
        limitMultiplier: 1,
        limitsAdjustmentEnabled: true,
        targetPercentile: 1,
    },
    hpaRule: {
        enabled: true,
        minReplicas: 2,
        maxReplicas: 6,
        targetUtilization: 0.70,
        targetMemoryUtilization: 0.80,
    },
    emergencyResponse: {
        oomEnabled: true,
        oomMemoryMultiplier: 1.5,
        cpuThrottlingEnabled: true,
        cpuThrottlingThreshold: 0.2,
        cpuThrottlingMultiplier: 1.25,
    },
    actionTriggers: ["on_schedule", "on_detection"],
    cronSchedule: "*/25 * * * *",
    detectionTriggers: ["pod_creation", "pod_update"],
}, { import: "rule-abc123" });

export const ruleId = rule.id;
import pulumi
from pulumi_devzero.resources import WorkloadRule, WorkloadRuleArgs
from pulumi_devzero.resources.types import (
    ResourceRuleConfigArgs,
    HPARuleConfigArgs,
    EmergencyResponseConfigArgs,
)

rule = WorkloadRule(
    "controller-manager-rule",
    args=WorkloadRuleArgs(
        cluster_id="cluster-abc123",
        namespace="devzero-system",
        kind="Deployment",
        name="controller-manager",
        auto_generate=False,
        cpu_rule=ResourceRuleConfigArgs(
            enabled=True,
            min_request=10,
            max_request=32000,
            limit_multiplier=1,
            limits_removal_enabled=True,
            target_percentile=0.85,
        ),
        memory_rule=ResourceRuleConfigArgs(
            enabled=True,
            min_request=67108864,
            max_request=68719476736,
            limit_multiplier=1,
            limits_adjustment_enabled=True,
            target_percentile=1,
        ),
        hpa_rule=HPARuleConfigArgs(
            enabled=True,
            min_replicas=2,
            max_replicas=6,
            target_utilization=0.70,
            target_memory_utilization=0.80,
        ),
        emergency_response=EmergencyResponseConfigArgs(
            oom_enabled=True,
            oom_memory_multiplier=1.5,
            cpu_throttling_enabled=True,
            cpu_throttling_threshold=0.2,
            cpu_throttling_multiplier=1.25,
        ),
        action_triggers=["on_schedule", "on_detection"],
        cron_schedule="*/25 * * * *",
        detection_triggers=["pod_creation", "pod_update"],
    ),
    opts=pulumi.ResourceOptions(import_="rule-abc123"),
)

pulumi.export("rule_id", rule.id)
package main

import (
    "github.com/devzero-inc/pulumi-provider-devzero/sdk/go/devzero/resources"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {
        rule, err := resources.NewWorkloadRule(ctx, "controller-manager-rule", &resources.WorkloadRuleArgs{
            ClusterId:    pulumi.String("cluster-abc123"),
            Namespace:    pulumi.String("devzero-system"),
            Kind:         pulumi.String("Deployment"),
            Name:         pulumi.String("controller-manager"),
            AutoGenerate: pulumi.BoolPtr(false),
            CpuRule: resources.ResourceRuleConfigArgsArgs{
                Enabled:              pulumi.BoolPtr(true),
                MinRequest:           pulumi.IntPtr(10),
                MaxRequest:           pulumi.IntPtr(32000),
                LimitMultiplier:      pulumi.Float64Ptr(1),
                LimitsRemovalEnabled: pulumi.BoolPtr(true),
                TargetPercentile:     pulumi.Float64Ptr(0.85),
            }.ToResourceRuleConfigArgsPtrOutput(),
            MemoryRule: resources.ResourceRuleConfigArgsArgs{
                Enabled:                 pulumi.BoolPtr(true),
                MinRequest:              pulumi.IntPtr(67108864),
                MaxRequest:              pulumi.IntPtr(68719476736),
                LimitMultiplier:         pulumi.Float64Ptr(1),
                LimitsAdjustmentEnabled: pulumi.BoolPtr(true),
                TargetPercentile:        pulumi.Float64Ptr(1),
            }.ToResourceRuleConfigArgsPtrOutput(),
            HpaRule: resources.HPARuleConfigArgsArgs{
                Enabled:                 pulumi.BoolPtr(true),
                MinReplicas:             pulumi.IntPtr(2),
                MaxReplicas:             pulumi.IntPtr(6),
                TargetUtilization:       pulumi.Float64Ptr(0.70),
                TargetMemoryUtilization: pulumi.Float64Ptr(0.80),
            }.ToHPARuleConfigArgsPtrOutput(),
            EmergencyResponse: resources.EmergencyResponseConfigArgsArgs{
                OomEnabled:              pulumi.BoolPtr(true),
                OomMemoryMultiplier:     pulumi.Float64Ptr(1.5),
                CpuThrottlingEnabled:    pulumi.BoolPtr(true),
                CpuThrottlingThreshold:  pulumi.Float64Ptr(0.2),
                CpuThrottlingMultiplier: pulumi.Float64Ptr(1.25),
            }.ToEmergencyResponseConfigArgsPtrOutput(),
            ActionTriggers:    pulumi.StringArray{pulumi.String("on_schedule"), pulumi.String("on_detection")},
            CronSchedule:      pulumi.StringPtr("*/25 * * * *"),
            DetectionTriggers: pulumi.StringArray{pulumi.String("pod_creation"), pulumi.String("pod_update")},
        }, pulumi.Import(pulumi.ID("rule-abc123")))
        if err != nil {
            return err
        }

        ctx.Export("ruleId", rule.ID())
        return nil
    })
}

Example — NodePolicy and target

NodePolicy selects node characteristics (architecture, capacity type, OS) and a disruption policy via direct operator/values selectors:

import * as pulumi from "@pulumi/pulumi";
import { resources } from "@devzero/pulumi-devzero";

const nodePolicy = new resources.NodePolicy("default-node-policy", {
    name: "default-node-policy",
    nodeClassName: "default",
    nodePoolName: "default",
    weight: 10,
    architectures: { operator: "In", values: ["arm64", "amd64"] },
    capacityTypes: { operator: "In", values: ["spot"] },
    disruption: {
        consolidationPolicy: "WhenEmptyOrUnderutilized",
        consolidateAfter: "2h",
        expireAfter: "168h",
        budgets: [
            { nodes: "100%", reasons: ["Empty"] },
            { nodes: "50%", reasons: ["Drifted"] },
        ],
    },
}, { import: "policy-abc123" });

export const nodePolicyId = nodePolicy.id;
import pulumi
from pulumi_devzero.resources import NodePolicy, NodePolicyArgs
from pulumi_devzero.resources.types import (
    LabelSelectorArgs,
    DisruptionPolicyArgs,
    DisruptionBudgetArgs,
)

node_policy = NodePolicy(
    "default-node-policy",
    args=NodePolicyArgs(
        name="default-node-policy",
        node_class_name="default",
        node_pool_name="default",
        weight=10,
        architectures=LabelSelectorArgs(operator="In", values=["arm64", "amd64"]),
        capacity_types=LabelSelectorArgs(operator="In", values=["spot"]),
        disruption=DisruptionPolicyArgs(
            consolidation_policy="WhenEmptyOrUnderutilized",
            consolidate_after="2h",
            expire_after="168h",
            budgets=[
                DisruptionBudgetArgs(nodes="100%", reasons=["Empty"]),
                DisruptionBudgetArgs(nodes="50%", reasons=["Drifted"]),
            ],
        ),
    ),
    opts=pulumi.ResourceOptions(import_="policy-abc123"),
)

pulumi.export("node_policy_id", node_policy.id)
package main

import (
    "github.com/devzero-inc/pulumi-provider-devzero/sdk/go/devzero/resources"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {
        nodePolicy, err := resources.NewNodePolicy(ctx, "default-node-policy", &resources.NodePolicyArgs{
            Name:          pulumi.String("default-node-policy"),
            NodeClassName: pulumi.StringPtr("default"),
            NodePoolName:  pulumi.StringPtr("default"),
            Weight:        pulumi.IntPtr(10),
            Architectures: &resources.LabelSelectorArgs{
                Operator: pulumi.String("In"),
                Values:   pulumi.StringArray{pulumi.String("arm64"), pulumi.String("amd64")},
            },
            CapacityTypes: &resources.LabelSelectorArgs{
                Operator: pulumi.String("In"),
                Values:   pulumi.StringArray{pulumi.String("spot")},
            },
            Disruption: resources.DisruptionPolicyArgsArgs{
                ConsolidationPolicy: pulumi.StringPtr("WhenEmptyOrUnderutilized"),
                ConsolidateAfter:    pulumi.StringPtr("2h"),
                ExpireAfter:         pulumi.StringPtr("168h"),
                Budgets: resources.DisruptionBudgetArgsArray{
                    resources.DisruptionBudgetArgsArgs{Nodes: pulumi.StringPtr("100%"), Reasons: pulumi.StringArray{pulumi.String("Empty")}},
                    resources.DisruptionBudgetArgsArgs{Nodes: pulumi.StringPtr("50%"), Reasons: pulumi.StringArray{pulumi.String("Drifted")}},
                },
            }.ToDisruptionPolicyArgsPtrOutput(),
        }, pulumi.Import(pulumi.ID("policy-abc123")))
        if err != nil {
            return err
        }

        ctx.Export("nodePolicyId", nodePolicy.ID())
        return nil
    })
}

Reading the diff

pulumi preview summarizes changed fields inline on the resource line, e.g.:

~ import devzero:resources:WorkloadPolicy iac-test [diff: -horizontalScaling~cpuVerticalScaling]
  • Fields after - exist on the live resource but are missing from your code. Applying would clear them.
  • Fields after ~ exist in both, but with different values. Applying would overwrite the live value with the one in your code.

This summary only tells you which fields differ, not the actual values. Run pulumi preview --diff to see the full before/after value for every changed field — use it to copy the exact live values into your code.

Supported resources

ResourceImport ID
ClusterCluster ID
WorkloadPolicyPolicy ID
WorkloadPolicyTargetTarget ID
WorkloadRuleRule ID
NodePolicyNode policy ID
NodePolicyTargetNode policy target ID

Tips

  • Import parent resources first. Import a Cluster before a WorkloadPolicyTarget or NodePolicyTarget that references its clusterIds, and a WorkloadPolicy/NodePolicy before the target(s) that reference its policyId — that way you can reference the parent's .id output instead of hardcoding the same ID twice.
  • Cluster tokens are not affected by import. Importing a Cluster never rotates or re-issues its token, so an already-connected in-cluster agent keeps working uninterrupted.

On this page