Go How-to

Generated from eve-iac OpenAPI/semantics. Do not edit manually.

Recipes for combining operations. The API reference explains each call. Examples assume an authenticated client and a packed project: lab, manifest, yaml, and files.

Model

YAML is IaC intent: what you want the lab to be. planProject previews the difference. reconcileProject with to_eve makes EVE match that intent. reconcileProject with from_eve turns the current EVE UNL definition into new IaC intent. It is not a capture of transient runtime state, and it is not importProject. getProjectStatus is the lightweight live poll. inspectProject is the rich structural snapshot.

IaC intent
    |
    | plan / reconcile
    v
EVE lab
    |
    +-> getProjectStatus
    |      lightweight live observation
    |
    +-> inspectProject
           rich structural observation

to_eve
YAML intent -> EVE

from_eve
current EVE UNL definition -> new YAML intent

Workflows

Observe a live lab

What this solves

Which nodes are alive right now, and which runtime link impairments are currently visible?

Mental model

What is alive right now?

Use these operations

Workflow

  1. Call getProjectStatus. Use inspectProject only when you need structure.
  2. If live is omitted, the project has no runtime lab.
  3. If live.available is false, the live read failed. nodes and netem are omitted. That is not an empty lab.
  4. If live.available is true, read live.nodes and live.netem. A missing netem side is effective delay 0, jitter 0, loss 0, bandwidth 0 and stays omitted.

Important semantics

  • This is the lightweight poll. An empty nodes array on a successful read means the lab has no nodes.
  • joined false means rows were read but they are not all mapped to IaC keys.
  • The status call stays HTTP 200 when the live read fails, so project context is still usable.

CLI: eve-iac status

Example

status, err := client.GetProjectStatus(ctx, eveiac.GetProjectStatusRequest{Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files})
if err != nil {
    return err
}
if status == nil || status.Live == nil {
    fmt.Println("no runtime lab")
    return nil
}
if status.Live.Available == nil || !*status.Live.Available {
    fmt.Println("runtime unavailable")
    return nil
}
for _, node := range status.Live.Nodes {
    key, label := "", ""
    if node.Key != nil {
        key = *node.Key
    }
    if node.StateLabel != nil {
        label = *node.StateLabel
    }
    fmt.Printf("%s: %s\n", key, label)
}
if status.Live.Netem != nil {
    for id, ifaces := range *status.Live.Netem {
        fmt.Printf("netem %s: %d interfaces\n", id, len(ifaces))
    }
}

Load the structural lab model

What this solves

What nodes, interfaces, and attachment points make up the current EVE lab?

Mental model

What does the current EVE lab look like?

Use these operations

Workflow

  1. Call inspectProject with refresh when you need a fresh structural snapshot.
  2. Read nodes and the interfaces on each node. Those interface names are the structural attachment points.
  3. Keep this snapshot. Do not repeat it as a live poll.
  4. For running or stopped state and runtime netem, switch to getProjectStatus.

Important semantics

  • inspectProject is the rich structural observation. It is not the high-frequency poll.
  • The canvas uses this snapshot to resolve node and interface identity, then overlays live state from getProjectStatus.
  • A missing netem side on a later status poll is effective zero impairment and is omitted.

CLI: eve-iac inspect --refresh

Example

observed, err := client.InspectProject(ctx, eveiac.InspectProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Refresh: eveiac.Ptr(true),
})
if err != nil {
    return err
}
for _, node := range observed.Nodes {
    key := ""
    if node.Key != nil {
        key = *node.Key
    }
    names := make([]string, 0, len(node.Interfaces))
    for _, iface := range node.Interfaces {
        if iface.Name != nil {
            names = append(names, *iface.Name)
        }
    }
    fmt.Printf("%s: %s\n", key, strings.Join(names, ","))
}

Build a live UI or monitoring loop

What this solves

How do I keep a structural picture of the lab and refresh only what is alive?

Mental model

Snapshot the shape once. Poll what is alive.

Use these operations

Workflow

  1. Inspect once, with refresh, and keep nodes plus their interfaces.
  2. Poll getProjectStatus on an interval your application chooses.
  3. When live.available is true, overlay node state and netem onto the structural model by native id.
  4. Inspect again only when interface names are missing, the topology changed, or the user asked for a structural refresh.
inspectProject(refresh=true)
        |
        v
structural model
        |
        +----------------+
                         |
                getProjectStatus
                getProjectStatus
                getProjectStatus
                         |
                         v
                 runtime overlay

Important semantics

  • A failed live read keeps the previous overlay. Do not replace netem with an empty object.
  • A missing netem side stays omitted. That means effective zero impairment.
  • Suspend is not on this poll. Read it from a structural inspect when you need it.

CLI: eve-iac inspect --refresh, then eve-iac status

Example

observed, err := client.InspectProject(ctx, eveiac.InspectProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Refresh: eveiac.Ptr(true),
})
if err != nil {
    return err
}
status, err := client.GetProjectStatus(ctx, eveiac.GetProjectStatusRequest{Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files})
if err != nil {
    return err
}
if status == nil || status.Live == nil || status.Live.Available == nil || !*status.Live.Available {
    fmt.Println("runtime unavailable")
    return nil
}
label := map[int]string{}
for _, row := range status.Live.Nodes {
    if row.ID != nil && row.StateLabel != nil {
        label[*row.ID] = *row.StateLabel
    }
}
observed.Netem = status.Live.Netem
for _, node := range observed.Nodes {
    if node.ID == nil {
        continue
    }
    fmt.Printf("%d: %s\n", *node.ID, label[*node.ID])
}

Plan changes without applying them

What this solves

What would change if I applied my current IaC intent?

Mental model

Preview the delta before mutation.

Use these operations

Workflow

  1. Call planProject. Omitted direction means to_eve.
  2. Read summary creates, updates, and deletes, and the action list.
  3. Keep plan_identity if a later to_eve confirm must stop nodes.
  4. Leave the plan as a preview. This call writes neither EVE nor the project files.
YAML intent
    +
EVE current state
    |
    v
plan

Important semantics

  • A plan identity belongs to one direction. Do not reuse a to_eve identity for from_eve.
  • applicable is a summary. It does not authorize the change.

CLI: eve-iac plan

Example

plan, err := client.PlanProject(ctx, eveiac.PlanProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Direction: eveiac.Ptr("to_eve"),
})
if err != nil {
    return err
}
creates := 0
if plan != nil && plan.Summary != nil && plan.Summary.Creates != nil {
    creates = *plan.Summary.Creates
}
fmt.Printf("creates=%d\n", creates)

Make EVE match IaC intent

What this solves

How do I apply the YAML intent to EVE?

Mental model

Make EVE match my IaC intent.

Use these operations

Workflow

  1. Plan with direction to_eve and read the actions.
  2. Reconcile with direction to_eve. Omitted confirm applies only live-safe work and does not stop nodes.
  3. If status is pending_stop, reconcile again with confirm true and the plan_identity from that same direction.
  4. An unsupported action means to_eve performs zero EVE mutations.

Important semantics

  • A later confirm reuses the plan_identity from this same direction. A missing or mismatched identity is 409 plan_stale and stops nothing.
  • Send direction to_eve on this recipe. from_eve is the other recipe.

CLI: eve-iac reconcile --direction to_eve

Example

plan, err := client.PlanProject(ctx, eveiac.PlanProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Direction: eveiac.Ptr("to_eve"),
})
if err != nil {
    return err
}
applied, err := client.ReconcileProject(ctx, eveiac.ReconcileProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Direction: eveiac.Ptr("to_eve"),
})
if err != nil {
    return err
}
if applied != nil && applied.Status != nil && *applied.Status == "pending_stop" && plan != nil && plan.PlanIdentity != nil {
    applied, err = client.ReconcileProject(ctx, eveiac.ReconcileProjectRequest{
        Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
        Direction: eveiac.Ptr("to_eve"), Confirm: eveiac.Ptr(true), PlanIdentity: plan.PlanIdentity,
    })
}

Make the current EVE lab definition the new intent

What this solves

I changed the EVE lab and now want that definition to become my IaC YAML intent. What do I do?

Mental model

Make the current EVE UNL definition my new IaC intent.

Use these operations

Workflow

  1. Reconcile with direction from_eve.
  2. Read the returned YAML intent and persist it in the project. The agent does not rewrite your files.
  3. Do not read node run state or netem out of this result and copy them into YAML.
EVE UNL definition
    -> Lab Object
    -> YAML intent

Important semantics

  • from_eve promotes the persisted EVE UNL definition. It is not a runtime capture.
  • It is not importProject. Import clones a lab into a managed copy and leaves YAML intent alone.
  • from_eve does not perform mutating EVE writes. confirm does not authorize a stop on this direction.

CLI: eve-iac reconcile --direction from_eve

Example

pulled, err := client.ReconcileProject(ctx, eveiac.ReconcileProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Direction: eveiac.Ptr("from_eve"),
})
if err != nil {
    return err
}
if pulled != nil && pulled.YAML != nil {
    fmt.Println("new IaC intent is ready to persist")
}

Start, stop, and wipe lab nodes

What this solves

How do I control node power and disks from an SDK?

Mental model

Start, stop, or wipe these nodes.

Use these operations

Workflow

  1. Read getCapabilities and the lifecycle flags for the project mode: create, import, or load.
  2. Call execProject with action start, stop, or wipe.
  3. Omit node to select every node. Pass nodes or node to select IaC keys.

Important semantics

  • Omitted stopmode is automatic. Explicit 0 is a graceful stop and is different from omitting the field.
  • Wipe clears node data. Destroying the lab is destroyProject, not wipe.

CLI: eve-iac exec start|stop|wipe

Example

caps, err := client.GetCapabilities(ctx)
if err != nil || caps == nil {
    return err
}
mode, ok := caps.ProjectModes["create"]
if !ok || mode.Lifecycle == nil {
    return nil
}
body := eveiac.ExecProjectRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
}
if mode.Lifecycle.Start != nil && *mode.Lifecycle.Start {
    body.Action = "start"
    _, err = client.ExecProject(ctx, body)
}
if err == nil && mode.Lifecycle.Stop != nil && *mode.Lifecycle.Stop {
    body.Action = "stop"
    body.Node = eveiac.Ptr("n_1")
    _, err = client.ExecProject(ctx, body)
}
if err == nil && mode.Lifecycle.Wipe != nil && *mode.Lifecycle.Wipe {
    body.Action = "wipe"
    _, err = client.ExecProject(ctx, body)
}
return err

Execute console commands

What this solves

How do I run commands against devices through EVE IaC?

Mental model

Talk to the node through the agent, not through a private console socket.

Use these operations

Workflow

  1. Use execConsole for one command on one node. The call returns when the prompt comes back.
  2. Use execConsoleMany when several nodes each get a command. One target's failure stays on that target.
  3. Use runConsole when the dialogue is an ordered expect and send. Use attachConsole and streamConsole for the live byte stream. A single show or ping stays on execConsole.

Important semantics

  • The SDK is the automation surface. Do not dial the EVE console transport yourself.
  • Omitted session joins or opens the console hub. A missing session is reopened once.

CLI: eve-iac console exec

Example

one, err := client.ExecConsole(ctx, eveiac.ExecConsoleRequest{
    Lab: eveiac.Ptr(lab), Node: eveiac.Ptr("n_1"), Command: eveiac.Ptr("show version"),
})
if err != nil {
    return err
}
if one != nil && one.Output != nil {
    fmt.Println(*one.Output)
}
_, err = client.ExecConsoleMany(ctx, eveiac.ExecConsoleManyRequest{
    Lab: eveiac.Ptr(lab),
    Targets: []eveiac.ConsoleTarget{{Node: eveiac.Ptr("n_1"), Command: eveiac.Ptr("show version")}},
})
return err

What this solves

How do I temporarily change latency, jitter, loss, or bandwidth on a live link?

Mental model

Impair this live link, then look again.

Use these operations

Workflow

  1. Read getProjectStatus and live.netem. A missing side is effective zero and is not present in the object.
  2. Call applyLinkQuality with the public YAML endpoints. Omitted save changes the live link only.
  3. Read getProjectStatus again. The sides you set are present. Sides you did not need to report stay omitted.

Important semantics

  • This is runtime interaction. It does not rewrite topology.yml.
  • save true asks EVE to persist the impairment in the UNL. That is still not an edit of IaC intent.
  • Omitted impairment on a side clears live netem on that side.

CLI: eve-iac link quality

Example

before, err := client.GetProjectStatus(ctx, eveiac.GetProjectStatusRequest{Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files})
if err != nil {
    return err
}
_ = before
_, err = client.ApplyLinkQuality(ctx, eveiac.ApplyLinkQualityRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Match: eveiac.PublicLinkMatch{Endpoints: []eveiac.PublicLinkEndpoint{
        {Node: eveiac.Ptr("n_1"), Interface: eveiac.Ptr("e0/0")},
        {Node: eveiac.Ptr("n_2"), Interface: eveiac.Ptr("e0/1")},
    }},
    SourceImpairment: &eveiac.LinkImpairment{Delay: eveiac.Ptr(50)},
})
if err != nil {
    return err
}
_, err = client.GetProjectStatus(ctx, eveiac.GetProjectStatusRequest{Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files})
return err

What this solves

How do I temporarily interrupt a live link?

Mental model

Pause or resume this live link.

Use these operations

Workflow

  1. Identify the link by its public YAML endpoints.
  2. Call setLinkSuspend with suspended true to interrupt it, or false to resume it.
  3. Omitted side means both node endpoints.

Important semantics

  • Suspend is runtime interaction. There is no topology.yml suspend field.
  • getProjectStatus does not carry suspend. A structural inspect does.

CLI: eve-iac link suspend / eve-iac link resume

Example

_, err := client.SetLinkSuspend(ctx, eveiac.SetLinkSuspendRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Match: eveiac.PublicLinkMatch{Endpoints: []eveiac.PublicLinkEndpoint{
        {Node: eveiac.Ptr("n_1"), Interface: eveiac.Ptr("e0/0")},
        {Node: eveiac.Ptr("n_2"), Interface: eveiac.Ptr("e0/1")},
    }},
    Suspended: true,
})
return err

Capture traffic

What this solves

How do I start a packet capture from an SDK?

Mental model

Capture packets on this interface.

Use these operations

Workflow

  1. Call startCapture with the IaC node key and the interface name.
  2. Open the returned HTML5 URL.
  3. Closing the page leaves the capture container running. The API has no stop call.

Important semantics

  • The URL is an HTML5 capture. evecapture:// is refused.
  • LOAD mode is allowed, the same way other runtime interaction is allowed.

Example

capture, err := client.StartCapture(ctx, eveiac.StartCaptureRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
    Node: "n_1", Interface: "e0/0",
})
if err != nil {
    return err
}
if capture != nil {
    fmt.Println(capture.URL)
}

Use traffic filters

What this solves

How do I describe selected traffic in IaC intent and then watch that stream?

Mental model

Describe the filter in intent. Watch the stream through the agent.

Use these operations

Workflow

  1. Read or edit traffic_filters on IaC intent with getPublicProject and editProject. That is the filter definition, not a live packet API.
  2. Call attachTraffic to receive a one-time ticket. Native EVE ids stay on the agent.
  3. Upgrade that ticket with streamTraffic and read the translated stream.

Important semantics

  • The filter is IaC intent, edited with editProject on section traffic_filters. The stream is runtime observation.
  • The SDK is the stream surface. Native EVE traffic sockets stay on the agent.

Example

attached, err := client.AttachTraffic(ctx, eveiac.AttachTrafficRequest{
    Lab: eveiac.Ptr(lab), Manifest: eveiac.Ptr(manifest), YAML: eveiac.Ptr(yaml), Files: files,
})
if err != nil || attached == nil {
    return err
}
ticket := attached.Stream
if i := strings.LastIndex(ticket, "/"); i >= 0 {
    ticket = ticket[i+1:]
}
_, err = client.StreamTraffic(ctx, ticket)
return err