Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
403 changes: 112 additions & 291 deletions README.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions apis/connectedendpointset/composition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Composition for ConnectedEndpointSet: validate this fragment and report on its own status.
# Uses the same function image as Fabric and Device, which dispatches on the
# composite kind.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: connectedendpointset-avd
spec:
compositeTypeRef:
apiVersion: avd.netclab.dev/v1alpha1
kind: ConnectedEndpointSet
mode: Pipeline
pipeline:
- step: validate-input
functionRef:
name: netclab-function-avd
106 changes: 106 additions & 0 deletions apis/connectedendpointset/xrd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# CompositeResourceDefinition for what connects to the fabric.
#
# Carries `connected_endpoints_keys.key` lists -- `servers`, `firewalls` and the
# rest -- plus `port_profiles` and `network_ports`. Its own kind for the same
# reason as NetworkServiceSet: whoever attaches servers is rarely whoever owns
# the fabric, and RBAC is granted per kind.
#
# Named ConnectedEndpointSet, not Endpoints: `Endpoints` is a core/v1 kind, so
# `kubectl get endpoints` would be ambiguous. The `Set` suffix is the family's --
# every input kind is a set of design entries of one category, carrying a scope --
# and it keeps the kind singular, so `connectedendpointset` and
# `connectedendpointsets` say different things the way `nodeset` does.
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
name: connectedendpointsets.avd.netclab.dev
spec:
scope: Namespaced
group: avd.netclab.dev
names:
kind: ConnectedEndpointSet
plural: connectedendpointsets
categories:
- crossplane
- netclab
defaultCompositionRef:
name: connectedendpointset-avd
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
design:
type: object
description: >-
The endpoints this input contributes. Structurally open:
the top-level key names come from connected_endpoints_keys,
so they are decided by the document's own content and no
OpenAPI schema can describe them.
x-kubernetes-preserve-unknown-fields: true
appliesTo:
type: object
description: >-
Devices that see this input. Defaults to every device in the
fabric.
properties:
all:
type: boolean
nodeSets:
type: array
description: Devices declared by the named NodeSets.
items:
type: string
hosts:
type: array
description: Devices named directly.
items:
type: string
matchHostnames:
type: array
description: >-
Regular expressions matched against device names. Same
semantics as AVD's own default_node_types, which matches
hostnames this way: the pattern is anchored for you, so
`dc1-leaf.*` matches the whole name. A pattern matching
no device is an error, not an empty set -- a pattern is
silent about both matching nothing and matching too much,
and the render is pushed as a full config replacement.
items:
type: string
required:
- design
status:
type: object
properties:
keys:
type: array
description: Top-level eos_designs keys this input contributes.
items:
type: string
devices:
type: array
description: >-
Devices this input resolved to. Reported rather than left to
be inferred, because appliesTo may be a pattern and a pattern
does not say what it matched.
items:
type: string
validation:
type: object
description: >-
Result of validating this fragment. Reported here rather than
on the Fabric so the team that owns this object sees its own
error on its own object.
properties:
ok:
type: boolean
message:
type: string
x-kubernetes-preserve-unknown-fields: true
3 changes: 3 additions & 0 deletions apis/device/xrd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ spec:
names:
kind: Device
plural: devices
categories:
- crossplane
- netclab
# Devices are composed by the Fabric function without an explicit composition
# selector; pin the default so selection is deterministic.
defaultCompositionRef:
Expand Down
78 changes: 76 additions & 2 deletions apis/fabric/xrd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ spec:
names:
kind: Fabric
plural: fabrics
categories:
- crossplane
- netclab
defaultCompositionRef:
name: fabric-avd
versions:
Expand All @@ -46,8 +49,74 @@ spec:
description: >-
Fabric-wide AVD eos_designs input document (node-type blocks,
default_node_types, tenants, connected endpoints, ...).
Validated by pyavd; violations reported on status.
Validated by pyavd; violations reported on status. A fabric
may instead be assembled from input objects listed in
spec.requires, in which case this carries only what is
fabric-wide and the inputs carry the rest.
x-kubernetes-preserve-unknown-fields: true
requires:
type: array
description: >-
The input objects composing this fabric. Only objects listed
here take part in the render, however they are labelled --
which is what makes the rendered document a function of this
Fabric rather than of whatever else exists in the namespace,
and it matters because the render is pushed as a full config
replacement. An entry that does not resolve leaves the Fabric
not ready, naming the object it could not find. List order is
the merge order: a later input replaces an earlier one's keys,
which is how a setting is narrowed to part of the fabric.
items:
type: object
properties:
kind:
type: string
enum:
- NodeSet
- NetworkServiceSet
- ConnectedEndpointSet
- SettingSet
- Secret
name:
type: string
minLength: 1
namespace:
type: string
description: >-
Namespace holding the object. Defaults to the Fabric's
own namespace.
required:
- kind
- name
nodeIdPool:
type: object
description: >-
Where this fabric's node IDs come from when the design sets
fabric_numbering.node_id.algorithm to pool_manager. AVD then
hands out IDs instead of reading them off each node, and
keeps the assignments in a file. There is no such file in a
cluster, so the Fabric composes a ConfigMap and reads it back
on the next reconcile. Nothing here is needed for a fabric
that numbers its nodes itself.
properties:
seedConfigMapName:
type: string
description: >-
A ConfigMap holding assignments to start from, read once
when this fabric has no pool of its own yet. It exists
for a fabric that was already running elsewhere: AVD
generated its IDs and they are in a file, and a fabric
that starts over assigns different ones - which reaches
every device as a full configuration replacement. Not
needed for a new fabric, and ignored once the composed
pool exists, so it seeds rather than overrides.
minLength: 1
seedKey:
type: string
description: >-
Key within that ConfigMap. Defaults to the key the
composed pool uses.
minLength: 1
push:
type: object
description: >-
Expand Down Expand Up @@ -86,9 +155,14 @@ spec:
description: cEOS serves a self-signed cert; default true.
required:
- credentialsSecretName
# `design` is NOT required: a fabric may be assembled entirely from
# the inputs named in `spec.requires`, which is what `avd-migrate`
# emits and what `fn.py` has always accepted ("design or requires").
# Requiring it here made every migrated Fabric unapplyable, and no
# offline test could see it -- they drive RunFunction directly and
# never meet the API server's schema.
required:
- fabricName
- design
status:
type: object
properties:
Expand Down
16 changes: 16 additions & 0 deletions apis/networkserviceset/composition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Composition for NetworkServiceSet: validate this fragment and report on its own status.
# Uses the same function image as Fabric and Device, which dispatches on the
# composite kind.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: networkserviceset-avd
spec:
compositeTypeRef:
apiVersion: avd.netclab.dev/v1alpha1
kind: NetworkServiceSet
mode: Pipeline
pipeline:
- step: validate-input
functionRef:
name: netclab-function-avd
104 changes: 104 additions & 0 deletions apis/networkserviceset/xrd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# CompositeResourceDefinition for a set of a fabric's network services.
#
# Carries the tenants -- `network_services_keys.name`, `tenants` by default --
# with their VRFs, SVIs and L2 VLANs. Its own kind because network services are
# owned by whoever runs the services, not by whoever owns the spines, and RBAC
# is granted per kind.
#
# It normally applies to every device: AVD decides per node which services land
# there, through `filter.tenants` and `filter.tags` on the node, so this input
# does not have to be scoped by hand.
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
name: networkservicesets.avd.netclab.dev
spec:
scope: Namespaced
group: avd.netclab.dev
names:
kind: NetworkServiceSet
plural: networkservicesets
categories:
- crossplane
- netclab
defaultCompositionRef:
name: networkserviceset-avd
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
design:
type: object
description: >-
The tenants this input contributes. Structurally open:
the top-level key names come from network_services_keys, so
they are decided by the document's own content and no OpenAPI
schema can describe them.
x-kubernetes-preserve-unknown-fields: true
appliesTo:
type: object
description: >-
Devices that see this input. Defaults to every device in the
fabric.
properties:
all:
type: boolean
nodeSets:
type: array
description: Devices declared by the named NodeSets.
items:
type: string
hosts:
type: array
description: Devices named directly.
items:
type: string
matchHostnames:
type: array
description: >-
Regular expressions matched against device names. Same
semantics as AVD's own default_node_types, which matches
hostnames this way: the pattern is anchored for you, so
`dc1-leaf.*` matches the whole name. A pattern matching
no device is an error, not an empty set -- a pattern is
silent about both matching nothing and matching too much,
and the render is pushed as a full config replacement.
items:
type: string
required:
- design
status:
type: object
properties:
keys:
type: array
description: Top-level eos_designs keys this input contributes.
items:
type: string
devices:
type: array
description: >-
Devices this input resolved to. Reported rather than left to
be inferred, because appliesTo may be a pattern and a pattern
does not say what it matched.
items:
type: string
validation:
type: object
description: >-
Result of validating this fragment. Reported here rather than
on the Fabric so the team that owns this object sees its own
error on its own object.
properties:
ok:
type: boolean
message:
type: string
x-kubernetes-preserve-unknown-fields: true
16 changes: 16 additions & 0 deletions apis/nodeset/composition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Composition for NodeSet: validate this fragment and report on its own status.
# Uses the same function image as Fabric and Device, which dispatches on the
# composite kind.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: nodeset-avd
spec:
compositeTypeRef:
apiVersion: avd.netclab.dev/v1alpha1
kind: NodeSet
mode: Pipeline
pipeline:
- step: validate-input
functionRef:
name: netclab-function-avd
Loading