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
- 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.
- Write the resource block, filling in as many fields as you know, and attach the ID using the
importoption (syntax below). - Run
pulumi preview --diff. This shows exactly which fields in your code don't match the live resource, with full before/after values. - Update your code to match the live values shown in the diff, and re-run
pulumi preview --diffuntil it shows a clean import with no changes. - Run
pulumi upto adopt the resource. - Remove the
importoption 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
| Resource | Import ID |
|---|---|
Cluster | Cluster ID |
WorkloadPolicy | Policy ID |
WorkloadPolicyTarget | Target ID |
WorkloadRule | Rule ID |
NodePolicy | Node policy ID |
NodePolicyTarget | Node policy target ID |
Tips
- Import parent resources first. Import a
Clusterbefore aWorkloadPolicyTargetorNodePolicyTargetthat references itsclusterIds, and aWorkloadPolicy/NodePolicybefore the target(s) that reference itspolicyId— that way you can reference the parent's.idoutput instead of hardcoding the same ID twice. - Cluster tokens are not affected by import. Importing a
Clusternever rotates or re-issues its token, so an already-connected in-cluster agent keeps working uninterrupted.