From d485ea3e597b694a1f93b0ff328b3aeefb3c5422 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Thu, 17 Oct 2024 17:00:55 -0400 Subject: [PATCH 01/37] initial commit --- docs/install-upgrade/build-wiring.md | 34 ++---- docs/install-upgrade/overview.md | 171 ++++++++------------------- docs/install-upgrade/requirements.md | 1 + 3 files changed, 60 insertions(+), 146 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 47743c4..ec983d9 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -3,36 +3,26 @@ !!! warning "" Under construction. -You can find mode details in the User Guide including [switch features and port naming](../user-guide/profiles.md). It's -mandatoy to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port -naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. +You can find more details in the User Guide including [switch features and port naming](../user-guide/profiles.md). It's mandatoy to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. In the meantime, to have a look at working wiring diagram for Hedgehog Fabric, run the sample generator that produces VLAB-compatible wiring diagrams: ```console -ubuntu@sl-dev:~$ hhfab wiring sample -h +ubuntu@sl-dev:~$ hhfab sample -h + NAME: - hhfab wiring sample - sample wiring diagram (would work for vlab) + hhfab sample - generate sample wiring diagram USAGE: - hhfab wiring sample [command options] [arguments...] + hhfab sample command [command options] + +COMMANDS: + spine-leaf, sl generate sample spine-leaf wiring diagram + collapsed-core, cc generate sample collapsed-core wiring diagram + help, h Shows a list of commands or help for one command OPTIONS: - --brief, -b brief output (only warn and error) (default: false) - --fabric-mode value, -m value fabric mode (one of: collapsed-core, spine-leaf) (default: "spine-leaf") - --help, -h show help - --verbose, -v verbose output (includes debug) (default: false) - - wiring generator options: - - --chain-control-link chain control links instead of all switches directly connected to control node if fabric mode is spine-leaf (default: false) - --control-links-count value number of control links if chain-control-link is enabled (default: 0) - --fabric-links-count value number of fabric links if fabric mode is spine-leaf (default: 0) - --mclag-leafs-count value number of mclag leafs (should be even) (default: 0) - --mclag-peer-links value number of mclag peer links for each mclag leaf (default: 0) - --mclag-session-links value number of mclag session links for each mclag leaf (default: 0) - --orphan-leafs-count value number of orphan leafs (default: 0) - --spines-count value number of spines if fabric mode is spine-leaf (default: 0) - --vpc-loopbacks value number of vpc loopbacks for each switch (default: 0) + --help, -h show help ``` + diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 6177b36..c2111dc 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -5,159 +5,82 @@ ## Prerequisites -* Have a machine with access to the Internet to use Fabricator and build installer -* Have a machine to install Fabric Control Node on with enough NICs to connect to at least one switch using Front Panel - ports and enough CPU and RAM (see [System Requirements](./requirements.md)) as well as IPMI access to it to install - the OS +* A machine with access to the Internet to use Fabricator and build installer +* An 8 GB USB flash drive, if you are not using virtual media +* Have a machine to function as the Fabric Control Node.[System Requirements](./requirements.md)) as well as IPMI access to it to install + the OS. +* Have a management switch with at least 1 10GbE port * Have enough [Supported Switches](./supported-devices.md) for your Fabric -## Main steps +## Overview of Install Process -This chapter is dedicated to the Hedgehog Fabric installation on bare-metal control node(s) and switches, their -preparation and configuration. +This section is dedicated to the Hedgehog Fabric installation on bare-metal control node(s) and switches, their +preparation and configuration. To install the vlab see [Vlab Overivew](../vlab/overview.md). -Get `hhfab` installed following instructions from the [Download](../getting-started/download.md) section. +Download and install `hhfab` following instructions from the [Download](../getting-started/download.md) section. The main steps to install Fabric are: 1. Install `hhfab` on the machines with access to the Internet 1. [Prepare Wiring Diagram](./build-wiring.md) - 1. [Select Fabric Configuration](./config.md) + 1. [Select Fabric Configuration](./config.md) // TODO - section on dhcp or ntp servers, the FAB.yaml 1. [Build Control Node configuration and installer](#build-control-node-configuration-and-installer) 1. [Install Control Node](#install-control-node) - 1. Install Flatcar Linux on the Control Node - 1. Upload and run Control Node installer on the Control Node + 1. Insert USB with control-os image into Fabric Control Node + 1. Boot the node off the USB to initiate the installation +1. Prepare Management Network + 1. Connect switch to Fabric control node + 1. Connect 1GbE Management ports of switches to control switch 1. Prepare supported switches - 1. [Install Hedgehog ONIE (HONIE) on them](./onie-update.md) - 1. Reboot them into ONIE Install Mode to have them automatically provisioned + 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and installer -It's the only step that requires Internet access, to download artifacts and build the installer. +### HHFAB commands +- `hhfab init --wiring wiring-lab.yaml` +- edit the `fab.yaml` file for your needs +- `hhfab validate` +- `hhfab build` -Once you've prepared the Wiring Diagram, initialize Fabricator by running `hhfab init` command and passing optional -configuration into it as well as wiring diagram file(s) as flags. Additionally, there are a lot of customizations -available as flags, e.g. to setup default credentials, keys and etc. For more details on the command invocation, -refer to `hhfab init --help`. - -The `--dev` option activates the development mode which enables default credentials and keys for the Control -Node and switches: - -* Default user with passwordless sudo for the Control Node and test servers is `core` with password `HHFab.Admin!`. -* Admin user with full access and passwordless sudo for the switches is `admin` with password `HHFab.Admin!`. -* Read-only, non-sudo user with access only to the switch CLI for the switches is `op` with password `HHFab.Op!`. - -Alternatively, you can pass your own credentials and keys using `--authorized-key` and `--control-password-hash` flags. -Generate a password hash with command `openssl passwd -5`. Further customization items are available in the config -file and can be passed using the `--config` flag. - -```bash -hhfab init --preset lab --dev --wiring file1.yaml --wiring file2.yaml -hhfab build -``` - -As a result, you will get the following files in the `.hhfab` directory or the one you've passed using `--basedir` flag: - -* `control-os/ignition.json` - ignition config for the Control Node to get OS installed -* `control-install.tgz` - installer for the Control Node, it will be uploaded to the Control Node and run there +### Burn USB image to disk +!!! warning "" + This will erase data on the usb disk. +- Insert the usb to your machine +- Identify the path to your usb stick for example `/dev/sdc` +- Issue the command to write the image to the usb drive + - `sudo dd if=/path/to/control-os/img of=/dev/sdc bs=4k status=progress` +There are utilities that assist this process such as [etcher](https://etcher.balena.io/). -More details on configuring the Fabric are available in the [Configuration](./config.md) section. +TODO - details on what comes out of each step +TODO - go to the config page to talk about the options inside the fab.yaml ## Install Control Node -### Connected Instructions This control node should be given a static IP address. Either a lease or statically assigned. -1. Download the [latest stable Flatcar Container Linux ISO ~400MiB][Flatcar ISO] - -[Flatcar ISO]: https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_iso_image.iso - -1. Bios boot the control node using the ISO, via virtual media, USB, or other way. - -1. Once the control node has booted it will auto login to a shell - -1. Upload the file `ignition.json` built during the previous step to the -system and run the Flatcar installation: - -```bash -sudo flatcar-install -d /dev/sda -i ignition.json -``` - -Where `/dev/sda` is a disk you want to install Control Node to and `ignition.json` is the `control-os/ignition.json` -file from previous step uploaded to the Flatcar installer. This installer reaches out to the publically available images to download, verify and install flatcar to the given disk. - -The installation is finished when you see a message similar to the following: - -```shell -Installing Ignition config ignition.json... -Success! Flatcar Container Linux stable 3510.2.6 is installed on /dev/sda -``` - -[Move on to the next step](#install-hedgehog-controller) - -### Air Gapped Instructions -Control Node installation is fully air-gapped and doesn't require Internet access. A static IP is still needed as command and control communications between the switches and controller use IP. The instructions are similar to above. - -1. Download the [latest stable Flatcar Container Linux ISO ~400MiB][Flatcar ISO] and bios boot into it (using IPMI attaching media, USB -stick or any other way). - -[Flatcar ISO]: https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_iso_image.iso - -1. Download the [latest stable Flatcar Container Linux Image ~500MiB][Flatcar Image] and copy that file to media that can be attached to the control node. -[Flatcar Image]: https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_image.bin.bz2 - -1. Copy the `control-os/ignition.json` file to the media from the above step. - -1. Bios boot the control node using the iso from above. - -1. Once the control node has booted, it will auto-login to a shell. - -1. Attach the media containing both the container image file and the ignition file to the booted control node. - -1. Uncompress the image `bunzip -d ./path/to/flatcar_production_image.bin.bz2`, if you want to keep the compressed image use the `-k` flag. - -```bash -sudo flatcar-install -d /dev/sda -i ignition.json -f flatcar_production_image.bin -``` - -Where `/dev/sda` is a disk you want to install Control Node to and `ignition.json` is the `control-os/ignition.json` -file from previous step uploaded to the Flatcar installer. By providing an image to the installer, no public internet connections will be attemtped. +1. Configure the server to use UEFI boot without secure boot -The installation is finished when you see a message similar to the following: +1. Attach the image to the server either by inserting via USB, or attaching via virtual media. After this step the process is automated -```shell -Installing Ignition config ignition.json... -Success! Flatcar Container Linux stable 3510.2.6 is installed on /dev/sda -``` -[Move on to the next step](#install-hedgehog-controller) +1. Once the control node has booted it will auto login and begin the installation process + 1. Optionally use ` journalctl -f -u flatcar-install.service` to monitor progress -### Install HedgeHog Controller +1. Once the install is complete the system will automatically reboot -Once the installation is finished, reboot the machine and wait for it to boot into the installed Flatcar Linux. +1. Upon booting into the freshly installed system, the fabric installation will automatically begin + 1. Optionally this can be monitored with `journalctl -f -u fabric-install.service` -At that point, you should get into the installed Flatcar Linux using the dev or provided credentials with user `core` -and you can now install Hedgehog Open Network Fabric on it. Download `control-install.tgz` to the just installed Control -Node (for example, by using scp) and run it. +1. The install is complete when the log emits "Control Node installation complete" + 1. Additionally the systemctl status will show `inactive (dead)` indicating that the executable has finished -```bash -tar xzf control-install.tgz && cd control-install && sudo ./hhfab-recipe run -``` -The command prints the logs generated while installing Fabric (including logs from the Kubernetes cluster, miscellaneous -OCI registry misc components, and more). At the end, you should observe lines similar to the following: +[Move on to the next step](#fabric-manages-switches) -``` -... -01:34:45 INF Running name=reloader-image op="push fabricator/reloader:v1.0.40" -01:34:47 INF Running name=reloader-chart op="push fabricator/charts/reloader:1.0.40" -01:34:47 INF Running name=reloader-install op="file /var/lib/rancher/k3s/server/manifests/hh-reloader-install.yaml" -01:34:47 INF Running name=reloader-wait op="wait deployment/reloader-reloader" -deployment.apps/reloader-reloader condition met -01:35:15 INF Done took=3m39.586394608s -``` +### Fabric Manages Switches -At that point, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all preinstalled -as part of the Control Node installer. +Now that the install has finished, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all preinstalled as part of the Control Node installer. -You can now get HONIE installed on your switches and reboot them into ONIE Install Mode to have them automatically -provisioned from the Control Node. +Now the fabric is handing out dhcp addresses to the switches via the management network. Optionally, to monitor this process: +- enter `k9s` at the command prompt +- use the arror keys to select the boot pod TODO (use the specific name) +- the logs of the pod will be displayed diff --git a/docs/install-upgrade/requirements.md b/docs/install-upgrade/requirements.md index 02ffa9a..e0b2b73 100644 --- a/docs/install-upgrade/requirements.md +++ b/docs/install-upgrade/requirements.md @@ -2,6 +2,7 @@ - Fast SSDs for system/root as well as Kubernetes and container runtime folders are required for stable work - SSDs are mandatory for Control Nodes +- 10 GbE port for connection to management network - Minimal (non-HA) setup is a single Control Node - (Future) Full (HA) setup is at least 3 Control Nodes - (Future) Extra nodes could be used for things like Logging, Monitoring, Alerting stack, and more From 0ea7756ff2664915bb2296315206b73fc031c297 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Fri, 18 Oct 2024 17:10:01 -0400 Subject: [PATCH 02/37] incremental commit --- docs/install-upgrade/config.md | 94 ++++++++++++++++++-------------- docs/install-upgrade/overview.md | 35 +++++++----- 2 files changed, 74 insertions(+), 55 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 83f2062..38efa73 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -9,22 +9,35 @@ use of on-demand DHCP for multiple IPv4/VLAN namespaces and overlapping IP ranges, and it adds DHCP leases into the Fabric API +```yaml +spec: + config + ... + fabric: + mode: spine-leaf + includeONIE: true + +``` + For more information about how to use `hhfab init`, run `hhfab init --help`. ## Configure switch users -It's currently only possible by using a config yaml file for the `hhfab init -c ` command. You can +It's currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: ```yaml -config: +spec: + config ... - fabric: + fabric: ... - switchUsers: - - name: test + defaultSwitchUsers: + admin: + role: admin password: $5$oj/NxDtFw3eTyini$VHwdjWXSNYRxlFMu.1S5ZlGJbUF/CGmCAZIBroJlax4 - role: operator + authorizedKeys: + - "ssh-ed25519 THISisAkeYFOrSShiNGtoHoSTs" ``` Where `name` is the username, `password` is the password hash created with `openssl passwd -5` command, and `role` is @@ -40,45 +53,44 @@ access the configured targets. It could be done by passing `--control-proxy=true Metrics includes port speeds, counters, errors, operational status, transceivers, fans, power supplies, temperature sensors, BGP neighbors, LLDP neighbors, and more. Logs include agent logs. -Configuring the exporters and targets is currently only possible by using a config yaml file for the +Configuring the exporters and targets is currently only possible by using a yaml configuration file for the `hhfab init -c ` command using the following format: ```yaml -config: - ... - fabric: - ... +spec: + config: + ... + defaultAlloyConfig: + agentScrapeIntervalSeconds: 120 + unixScrapeIntervalSeconds: 120 + unixExporterEnabled: true controlProxy: true # (optional) same as passing --control-proxy=true to hhfab init - alloy: - agentScrapeIntervalSeconds: 120 - controlProxyURL: http://172.30.1.1:31028 - lokiTargets: - grafana_cloud: # target name, multiple targets can be configured - basicAuth: # optional - password: "" - username: "" - labels: # labels to be added to all logs - env: env-1 - url: https://logs-prod-021.grafana.net/loki/api/v1/push - useControlProxy: true # if the Loki API is not available from the switches directly, use the Control Node as a proxy - prometheusTargets: - grafana_cloud: # target name, multiple targets can be configured - basicAuth: # optional - password: "" - username: "" - labels: # labels to be added to all metrics - env: env-1 - sendIntervalSeconds: 120 - url: https://prometheus-prod-36-prod-us-west-0.grafana.net/api/prom/push - useControlProxy: true # if the Loki API is not available from the switches directly, use the Control Node as a proxy - unixExporterCollectors: # list of node-exporter collectors to enable, https://grafana.com/docs/alloy/latest/reference/components/prometheus.exporter.unix/#collectors-list - - cpu - - filesystem - - loadavg - - meminfo - unixExporterEnabled: true - unixScrapeIntervalSeconds: 120 - collectSyslogEnabled: true # collect /var/log/syslog on switches and forward to the lokiTargets + controlProxyURL: http://172.30.1.1:31028 + lokiTargets: + grafana_cloud: # target name, multiple targets can be configured + basicAuth: # optional + password: "" + username: "" + labels: # labels to be added to all logs + env: env-1 + url: https://logs-prod-021.grafana.net/loki/api/v1/push + useControlProxy: true # if the Loki API is not available from the switches directly, use the Control Node as a proxy + prometheusTargets: + grafana_cloud: # target name, multiple targets can be configured + basicAuth: # optional + password: "" + username: "" + labels: # labels to be added to all metrics + env: env-1 + sendIntervalSeconds: 120 + url: https://prometheus-prod-36-prod-us-west-0.grafana.net/api/prom/push + useControlProxy: true # if the Loki API is not available from the switches directly, use the Control Node as a proxy + unixExporterCollectors: # list of node-exporter collectors to enable, https://grafana.com/docs/alloy/latest/reference/components/prometheus.exporter.unix/#collectors-list + - cpu + - filesystem + - loadavg + - meminfo + collectSyslogEnabled: true # collect /var/log/syslog on switches and forward to the lokiTargets ``` For additional options, see the `AlloyConfig` [struct in Fabric repo](https://github.com/githedgehog/fabric/blob/master/api/meta/alloy.go). diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index c2111dc..bc2ea5c 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -15,7 +15,7 @@ ## Overview of Install Process This section is dedicated to the Hedgehog Fabric installation on bare-metal control node(s) and switches, their -preparation and configuration. To install the vlab see [Vlab Overivew](../vlab/overview.md). +preparation and configuration. To install the vlab see [Vlab Overview](../vlab/overview.md). Download and install `hhfab` following instructions from the [Download](../getting-started/download.md) section. @@ -34,13 +34,17 @@ The main steps to install Fabric are: 1. Prepare supported switches 1. Boot them into ONIE Install Mode to have them automatically provisioned -## Build Control Node configuration and installer +## Build Control Node configuration and Installer +Hedgehog has created a command line utility, called `hhfab`, that will help generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a disk. -### HHFAB commands -- `hhfab init --wiring wiring-lab.yaml` -- edit the `fab.yaml` file for your needs -- `hhfab validate` -- `hhfab build` +### HHFAB commands to make a bootable image +1. `hhfab init --wiring wiring-lab.yaml` +1. edit the `fab.yaml` file for your needs + 1. ensure the correct boot disk (eg `/dev/sda`) and control node NIC names are supplied +1. `hhfab validate` +1. `hhfab build --usb` + +The installer for the fabric will be generated in `$WORKDIR/result`. This installation image is 7.5 GB in size. ### Burn USB image to disk !!! warning "" @@ -49,18 +53,19 @@ The main steps to install Fabric are: - Identify the path to your usb stick for example `/dev/sdc` - Issue the command to write the image to the usb drive - `sudo dd if=/path/to/control-os/img of=/dev/sdc bs=4k status=progress` + There are utilities that assist this process such as [etcher](https://etcher.balena.io/). -TODO - details on what comes out of each step -TODO - go to the config page to talk about the options inside the fab.yaml ## Install Control Node This control node should be given a static IP address. Either a lease or statically assigned. -1. Configure the server to use UEFI boot without secure boot +1. Configure the server to use UEFI boot **without** secure boot + +1. Attach the image to the server either by inserting via USB, or attaching via virtual media. -1. Attach the image to the server either by inserting via USB, or attaching via virtual media. After this step the process is automated +1. Select boot off of the attached media, after this step the process is **automated**. The remaining steps are for your knowledge 1. Once the control node has booted it will auto login and begin the installation process 1. Optionally use ` journalctl -f -u flatcar-install.service` to monitor progress @@ -78,9 +83,11 @@ This control node should be given a static IP address. Either a lease or statica ### Fabric Manages Switches -Now that the install has finished, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all preinstalled as part of the Control Node installer. +Now that the install has finished, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all pre-installed as part of the Control Node installer. Now the fabric is handing out dhcp addresses to the switches via the management network. Optionally, to monitor this process: - enter `k9s` at the command prompt -- use the arror keys to select the boot pod TODO (use the specific name) -- the logs of the pod will be displayed +- use the arrow keys to select the boot pod TODO (use the specific name) +- the logs of the pod will be displayed showing the dhcp lease process +- use the switches screen of `k9s` to see the heartbeat column to verify the connection between switch and controller. + - to see the switches type `:switches` (like a vim command) into `k9s` From e9c3f9cf530b2d5b80b01c6c5b0dd03537dbaf55 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Mon, 21 Oct 2024 22:19:37 -0400 Subject: [PATCH 03/37] incremental commit --- docs/install-upgrade/build-wiring.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index ec983d9..d643372 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -3,7 +3,7 @@ !!! warning "" Under construction. -You can find more details in the User Guide including [switch features and port naming](../user-guide/profiles.md). It's mandatoy to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. +You can find more details in the User Guide including [switch features and port naming](../user-guide/profiles.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. In the meantime, to have a look at working wiring diagram for Hedgehog Fabric, run the sample generator that produces VLAB-compatible wiring diagrams: @@ -26,3 +26,27 @@ OPTIONS: --help, -h show help ``` +# Design Discussion +This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. This discussion starts with the primary building block, a VPC + +## VPC + +A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC will see each other but nothing else, the hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. + +## Connection + +A connection represents the physical wires in your data center. They connect switches to other switches or switches to servers. + +### Server Connections + +A server connection will require server side configuration as the Fabric configuration abilities do not reach into the end hosts. A server connection can be one of: + +- *Unbundled* - a single cable going from switch to server +- *Bundled* - two or more cables going to a single switch, the server needs to configured for this, Fabric handles the switch +- *MCLAG* - two cables going to two different switches, also called dual homing. The switches will need a fabric link between them +- *ESLAG* - two to four cables going to different switches, also called multi-homing. If four links are used there will be four switches connected to a single server with four NIC ports + +### Fabric Connections + +These serve as connection between switches, their beautiful weave comprise the fabric of the network. + From b1ac9b4d20eb5bc7f8d32a59a026a47600f54d19 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 15:25:37 -0400 Subject: [PATCH 04/37] more work on wiriging diagram design, and install section --- docs/install-upgrade/build-wiring.md | 42 ++++++++++++++++++++++------ docs/install-upgrade/overview.md | 16 ++++++++--- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index d643372..218e352 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -3,7 +3,9 @@ !!! warning "" Under construction. -You can find more details in the User Guide including [switch features and port naming](../user-guide/profiles.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. +## Overview + +A wiring diagram is a yaml file that is a digital representation of your network. You can find more yaml level details in the User Guide section [switch features and port naming](../user-guide/profiles.md) and the [api](../reference/api.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. In the meantime, to have a look at working wiring diagram for Hedgehog Fabric, run the sample generator that produces VLAB-compatible wiring diagrams: @@ -26,18 +28,18 @@ OPTIONS: --help, -h show help ``` -# Design Discussion -This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. This discussion starts with the primary building block, a VPC +## Design Discussion +This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. This discussion starts with the primary building block of your design, a VPC. -## VPC +### VPC -A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC will see each other but nothing else, the hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. +A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC will see each other but nothing else. The hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. -## Connection +### Connection A connection represents the physical wires in your data center. They connect switches to other switches or switches to servers. -### Server Connections +#### Server Connections A server connection will require server side configuration as the Fabric configuration abilities do not reach into the end hosts. A server connection can be one of: @@ -46,7 +48,29 @@ A server connection will require server side configuration as the Fabric configu - *MCLAG* - two cables going to two different switches, also called dual homing. The switches will need a fabric link between them - *ESLAG* - two to four cables going to different switches, also called multi-homing. If four links are used there will be four switches connected to a single server with four NIC ports -### Fabric Connections +#### Fabric Connections + +These serve as connection between switches, their beautiful weave comprises the fabric of the network. + + +### VPC Peering + +This is what is needed for VPCs to talk to each other. There are two varieties local and remote. + +#### Local VPC Peering + +When the VPCs that need to communicate are both on the same switch. An example would be if your database and web front end servers are in the same rack and are able to be physically cabled to the same switch. + +#### Remote VPC Peering + +When the VPCs that need to communicate are on different switches. An example would be if your storage and compute servers are in opposite ends of the data center and need to be cabled to different switches. + + + +## Design Examples + +### TODO - show the wiring diagram for a leaf-spine -These serve as connection between switches, their beautiful weave comprise the fabric of the network. +### TODO - show how to connect to an AWS cloud connection +### TODO - show how to connect to a provider ISP like equinix diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index bc2ea5c..baea04f 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -7,7 +7,7 @@ * A machine with access to the Internet to use Fabricator and build installer * An 8 GB USB flash drive, if you are not using virtual media -* Have a machine to function as the Fabric Control Node.[System Requirements](./requirements.md)) as well as IPMI access to it to install +* Have a machine to function as the Fabric Control Node. [System Requirements](./requirements.md) as well as IPMI access to it to install the OS. * Have a management switch with at least 1 10GbE port * Have enough [Supported Switches](./supported-devices.md) for your Fabric @@ -35,20 +35,21 @@ The main steps to install Fabric are: 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and Installer -Hedgehog has created a command line utility, called `hhfab`, that will help generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a disk. +Hedgehog has created a command line utility, called `hhfab`, that will help generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` 1. edit the `fab.yaml` file for your needs 1. ensure the correct boot disk (eg `/dev/sda`) and control node NIC names are supplied 1. `hhfab validate` -1. `hhfab build --usb` +1. `hhfab build` -The installer for the fabric will be generated in `$WORKDIR/result`. This installation image is 7.5 GB in size. +The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img ### Burn USB image to disk !!! warning "" This will erase data on the usb disk. + - Insert the usb to your machine - Identify the path to your usb stick for example `/dev/sdc` - Issue the command to write the image to the usb drive @@ -72,6 +73,8 @@ This control node should be given a static IP address. Either a lease or statica 1. Once the install is complete the system will automatically reboot +1. After the system has shutdown but before it boots up, remove the usb image from the system. Doing this during the uefi boot screen is acceptable. + 1. Upon booting into the freshly installed system, the fabric installation will automatically begin 1. Optionally this can be monitored with `journalctl -f -u fabric-install.service` @@ -81,6 +84,11 @@ This control node should be given a static IP address. Either a lease or statica [Move on to the next step](#fabric-manages-switches) + +### Configure Management Network + +The control node is dual homed. It has a 10GbE interface that connects to the managment network. The other link called `external` in the `fab.yaml` file is for the customer to access the control node. + ### Fabric Manages Switches Now that the install has finished, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all pre-installed as part of the Control Node installer. From 7e34daf93f2147bee8fc54ad2e632e9a02e12294 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 15:59:39 -0400 Subject: [PATCH 05/37] we no longer have honie and so we can delete this section --- .../install-upgrade/onie-update-grub-onie.png | Bin 58978 -> 0 bytes .../onie-update-onie-install.png | Bin 87427 -> 0 bytes docs/install-upgrade/onie-update.md | 95 ------------------ 3 files changed, 95 deletions(-) delete mode 100644 docs/install-upgrade/onie-update-grub-onie.png delete mode 100644 docs/install-upgrade/onie-update-onie-install.png delete mode 100644 docs/install-upgrade/onie-update.md diff --git a/docs/install-upgrade/onie-update-grub-onie.png b/docs/install-upgrade/onie-update-grub-onie.png deleted file mode 100644 index 71d0baa4b2f0ba418a53093e787e9de9327b2f2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58978 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 J!W$2t{trmI{X+l% diff --git a/docs/install-upgrade/onie-update-onie-install.png b/docs/install-upgrade/onie-update-onie-install.png deleted file mode 100644 index d4fe345e9162ba0c9a0773bb2f473e442b6f951b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87427 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

hM8 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 b?0DY5lgjd>*P*%w{=F8Jep&cJ`@{bMHTCQa diff --git a/docs/install-upgrade/onie-update.md b/docs/install-upgrade/onie-update.md deleted file mode 100644 index a810d45..0000000 --- a/docs/install-upgrade/onie-update.md +++ /dev/null @@ -1,95 +0,0 @@ -# ONIE Update/Upgrade - -## Hedgehog ONIE (HONIE) Supported Systems - -* DELL - * S5248F-ON - * S5232F-ON - -* Edge-Core - * DCS501 (AS7726-32X) - * DCS203 (AS7326-56X) - * EPS203 (AS4630-54NPE) - -## Updating ONIE - -### Via USB - -This example shows how to update a DELL S5248 to Hedgehog ONIE (HONIE). - -!!! note "" - Note: the USB port is on the back of the switch with the Management and Console. - -1. Prepare the USB stick by burning the honie-usb.img to a 4G or larger USB drive. - -2. Insert the USB drive into the switch. For example, burn the file to disk `X` of a macOS machine with - `sudo dd if=honie-usb.img of=/dev/rdiskX bs=1m`. - -3. Boot into ONIE Installer - - * First select ONIE: - ![](./onie-update-grub-onie.png) - - * Then request the installation: - ![](./onie-update-onie-install.png) - -4. ONIE will install the ONIE update and reboot. Here are some sample logs: - - ```hl_lines="3 38" - ONIE: OS Install Mode ... - Platform  : x86_64-dellemc_s5200_c3538-r0 - Version   : 3.40.1.1-7 <- Non HONIE version - Build Date: 2020-03-24T20:44-07:00 - Info: Mounting EFI System on /boot/efi ... - Info: BIOS mode: UEFI - Info: Making NOS install boot mode persistent. - Info: Using eth0 MAC address: 3c:2c:30:66:f0:00 - Info: eth0:  Checking link... up. - Info: Trying DHCPv4 on interface: eth0 - Warning: Unable to configure interface using DHCPv4: eth0 - ONIE: Using link-local IPv4 addr: eth0: 169.254.95.249/16 - Starting: klogd... done. - Starting: dropbear ssh daemon... done. - Starting: telnetd... done. - discover: installer mode detected.  Running installer. - Starting: discover... done. - Please press Enter to activate this console. Info: eth0:  Checking link... up. - Info: Trying DHCPv4 on interface: eth0 - Warning: Unable to configure interface using DHCPv4: eth0 - ONIE: Using link-local IPv4 addr: eth0: 169.254.6.139/16 - ONIE: Starting ONIE Service Discovery - Info: Attempting file://dev/sdb1/onie-installer-x86_64-dellemc_s5248f_c3538-r0 ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64-dellemc_s5248f_c3538-r0 ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64-dellemc_s5248f_c3538-r0.bin ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64-dellemc_s5248f_c3538.bin ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-dellemc_s5248f_c3538 ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-dellemc_s5248f_c3538.bin ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64-bcm ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64-bcm.bin ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64 ... - Info: Attempting file://dev/mmcblk0p1/onie-installer-x86_64.bin ... - Info: Attempting file://dev/mmcblk0p1/onie-installer ... - Info: Attempting file://dev/mmcblk0p1/onie-installer.bin ... - ONIE: Executing installer: file://dev/sdb1/onie-installer-x86_64-dellemc_s5248f_c3538-r0 - Verifying image checksum ... OK. - Preparing image archive ... OK. - ONIE: Version       : 3.40.1.1-8 <- HONIE Version - ONIE: Architecture  : x86_64 - ONIE: Machine       : dellemc_s5200_c3538 - ONIE: Machine Rev   : 0 - ONIE: Config Version: 1 - ONIE: Build Date    : 2023-12-15T23:43+00:00 - Installing ONIE on: /dev/sda - ONIE: NOS install successful: file://dev/sdb1/onie-installer-x86_64-dellemc_s5248f_c3538-r0 - ONIE: Rebooting... - discover: installer mode detected. - Stopping: discover...start-stop-daemon: warning: killing process 665: No such process - Info: Unmounting kernel filesystems - umount: can't unmount /: Invalid argument - The system is going down NOW! - Sent SIGTERM to all processes - Sent SIGKILL to all processes - Requesting system reboot - ``` - -5. The system is now ready for use. From 254eb94d5007b0355b6a6acfe4c94b14727b29ab Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 16:00:26 -0400 Subject: [PATCH 06/37] more words --- docs/install-upgrade/overview.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index baea04f..c2df403 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -39,14 +39,14 @@ Hedgehog has created a command line utility, called `hhfab`, that will help gene ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` -1. edit the `fab.yaml` file for your needs - 1. ensure the correct boot disk (eg `/dev/sda`) and control node NIC names are supplied +1. The `init` command will generate a `fab.yaml` file, edit the `fab.yaml` file for your needs + 1. ensure the correct boot disk (e.g. `/dev/sda`) and control node NIC names are supplied 1. `hhfab validate` 1. `hhfab build` -The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img +The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img. Once the image is created, it can be written to a USB drive, or mounted via virtual media. -### Burn USB image to disk +### Write USB image to disk !!! warning "" This will erase data on the usb disk. @@ -64,30 +64,28 @@ This control node should be given a static IP address. Either a lease or statica 1. Configure the server to use UEFI boot **without** secure boot -1. Attach the image to the server either by inserting via USB, or attaching via virtual media. +1. Attach the image to the server either by inserting via USB, or attaching via virtual media -1. Select boot off of the attached media, after this step the process is **automated**. The remaining steps are for your knowledge +1. Select boot off of the attached media, the installation process is **automated** 1. Once the control node has booted it will auto login and begin the installation process 1. Optionally use ` journalctl -f -u flatcar-install.service` to monitor progress 1. Once the install is complete the system will automatically reboot -1. After the system has shutdown but before it boots up, remove the usb image from the system. Doing this during the uefi boot screen is acceptable. +1. After the system has shutdown but before the boot up process reaches the operating system, **remove the usb image from the system**. Removal this during the uefi boot screen is acceptable. -1. Upon booting into the freshly installed system, the fabric installation will automatically begin +1. Upon booting into the freshly installed system, the fabric installation will **automatically begin** + 1. If the insecure `--dev` flag was passed to `hhfab init` the password for the `core` user is `HHFab.Admin!`, the switches have two users created `admin` and `op`. `admin` has administrator privileges and password `HHFab.Admin!`, the op user is a read only, non sudo user with password, `HHFab.Op!`. 1. Optionally this can be monitored with `journalctl -f -u fabric-install.service` 1. The install is complete when the log emits "Control Node installation complete" 1. Additionally the systemctl status will show `inactive (dead)` indicating that the executable has finished -[Move on to the next step](#fabric-manages-switches) - - ### Configure Management Network -The control node is dual homed. It has a 10GbE interface that connects to the managment network. The other link called `external` in the `fab.yaml` file is for the customer to access the control node. +The control node is dual homed. It has a 10GbE interface that connects to the managment network. The other link called `external` in the `fab.yaml` file is for the customer to access the control node. The management network is for the command and control of the switches that comprise the fabric. This management network can be a simple broadcast domain with layer 2 connectivity. The control node will run a dhcp and small http server. The management network shall not be accessible to machine or devices not associated with the fabric. ### Fabric Manages Switches From 4ef1222a73af24bbb620c6e6c28180e9b52cfa0d Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 17:15:56 -0400 Subject: [PATCH 07/37] added example files --- docs/install-upgrade/config.md | 171 +++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 41 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 38efa73..5746a25 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -1,49 +1,17 @@ # Fabric Configuration +## Overview +The `fab.yaml` file is the configuration file for the fabric. It supplies the configuration of the users, their credentials, logging, telemetry, and other non wiring related settings. The `fab.yaml` file is composed of multiple yaml documents inside of a single file. Per the yamls spec 3 hyphens (`---`) on a single line separate the end of one document from the beginning of the next. There are two yaml documents in the `fab.yaml` file. For more information about how to use `hhfab init`, run `hhfab init --help`. -* `--fabric-mode `- Comma-separated list of NTP servers to use, default is - `time.cloudflare.com,time1.google.com,time2.google.com,time3.google.com,time4.google.com`, it'll be used for both - control nodes and switches -* `--dhcpd ` (`isc` or `hedgehog`) - DHCP server to use, default is `isc`; `hedgehog` DHCP server enables - use of on-demand DHCP for multiple IPv4/VLAN namespaces and overlapping IP ranges, and it adds DHCP leases - into the Fabric API +## Fabric -```yaml -spec: - config - ... - fabric: - mode: spine-leaf - includeONIE: true - -``` - -For more information about how to use `hhfab init`, run `hhfab init --help`. - -## Configure switch users - -It's currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can -specify users to be configured on the switches in the following format: - -```yaml -spec: - config - ... - fabric: - ... - defaultSwitchUsers: - admin: - role: admin - password: $5$oj/NxDtFw3eTyini$VHwdjWXSNYRxlFMu.1S5ZlGJbUF/CGmCAZIBroJlax4 - authorizedKeys: - - "ssh-ed25519 THISisAkeYFOrSShiNGtoHoSTs" -``` +The fabric yaml object has 4 objects: -Where `name` is the username, `password` is the password hash created with `openssl passwd -5` command, and `role` is -the role of the user, one of `admin` or `operator` (read-only access to `sonic-cli` command on the switches). In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. +- `mode` - either `spine-leaf` or `collapsed-core` +- `includeONIE` - defaults to true +- `defaultSwitchUsers` - the admin and operator credentials for SONiC. +- `defaultAlloyConfig` - The configuration details for telemetry of switch information -## Forward switch metrics and logs +### Forward switch metrics and logs There is an option to enable Grafana Alloy on all switches to forward metrics and logs to the configured targets using Prometheus Remote-Write API and Loki API. If those APIs are available from Control Node(s), but not from the switches, @@ -94,3 +62,124 @@ spec: ``` For additional options, see the `AlloyConfig` [struct in Fabric repo](https://github.com/githedgehog/fabric/blob/master/api/meta/alloy.go). + +### Configure switch users + +It's currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: +```yaml +spec: + config: + control: + defaultUser: # user 'core' on all control nodes + password: "hashhashhashhashhash" # password hash + authorizedKeys: + - "ssh-ed25519 SecREKeyJumblE" + + fabric: + mode: spine-leaf # "spine-leaf" or "collapsed-core" + + defaultSwitchUsers: + admin: # at least one user with name 'admin' and role 'admin' + role: admin + #password: "$5$8nAYPGcl4..." # password hash + #authorizedKeys: # optional SSH authorized keys + # - "ssh-ed25519 AAAAC3Nza..." + op: # optional read-only user + role: operator + #password: "$5$8nAYPGcl4..." # password hash + #authorizedKeys: # optional SSH authorized keys + # - "ssh-ed25519 AAAAC3Nza..." + +``` +The role of the user,`operator` is read-only access to `sonic-cli` command on the switches. In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. + +## Control Node +This is the yaml document configure the control node: +```yaml +apiVersion: fabricator.githedgehog.com/v1beta1 +kind: ControlNode +metadata: + name: control-1 + namespace: fab +spec: + bootstrap: + disk: "/dev/sda" # disk to install OS on, e.g. "sda" or "nvme0n1" + external: + interface: enp2s0 # interface for external + ip: dhcp # IP address for external interface + management: + interface: enp2s1 # interface for management + +# Currently only one ControlNode is supported +``` +The **management** interface is for the control node to manage the fabric switches, *not* end-user management of the control node. For end user management of the control node specify the **external** interface name. + +## Complete Example File +```yaml +apiVersion: fabricator.githedgehog.com/v1beta1 +kind: Fabricator +metadata: + name: default + namespace: fab +spec: + config: + control: + tlsSAN: # IPs and DNS names that will be used to access API + - "env-2.l.hhdev.io" + + defaultUser: # user 'core' on all control nodes + password: "hash..." # password hash + authorizedKeys: + - "ssh-ed25519 hash..." + + fabric: + mode: spine-leaf # "spine-leaf" or "collapsed-core" + includeONIE: true + defaultSwitchUsers: + admin: # at least one user with name 'admin' and role 'admin' + role: admin + password: "hash..." # password hash + authorizedKeys: + - "ssh-ed25519 hash..." + op: # optional read-only user + role: operator + password: "hash..." # password hash + authorizedKeys: + - "ssh-ed25519 hash..." + + defaultAlloyConfig: + agentScrapeIntervalSeconds: 120 + unixScrapeIntervalSeconds: 120 + unixExporterEnabled: true + collectSyslogEnabled: true + lokiTargets: + lab: + url: http://url.io:3100/loki/api/v1/push + useControlProxy: true + labels: + descriptive: name + prometheusTargets: + lab: + url: http://url.io:9100/api/v1/push + useControlProxy: true + labels: + descriptive: name + sendIntervalSeconds: 120 + +--- +apiVersion: fabricator.githedgehog.com/v1beta1 +kind: ControlNode +metadata: + name: control-1 + namespace: fab +spec: + bootstrap: + disk: "/dev/sda" # disk to install OS on, e.g. "sda" or "nvme0n1" + external: + interface: eno2 # interface for external + ip: dhcp # IP address for external interface + management: + interface: eno1 + +# Currently only one ControlNode is supported +``` From 88296d53e1c3f18b417f0a1f463ed9052d238bec Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 20:52:09 -0400 Subject: [PATCH 08/37] Update docs/install-upgrade/build-wiring.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/build-wiring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 218e352..99ec9bb 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -29,7 +29,7 @@ OPTIONS: ``` ## Design Discussion -This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. This discussion starts with the primary building block of your design, a VPC. +This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. ### VPC From d4c9f6767902e65bb01f3f676e72d6e055d28ead Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 20:53:57 -0400 Subject: [PATCH 09/37] Update docs/install-upgrade/build-wiring.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/build-wiring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 99ec9bb..9a5d397 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -50,7 +50,7 @@ A server connection will require server side configuration as the Fabric configu #### Fabric Connections -These serve as connection between switches, their beautiful weave comprises the fabric of the network. +Fabric connections serve as connections between switches, they form the fabric of the network. ### VPC Peering From 63ccde21a793c5d865dee49f3176663bb526f095 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 21:02:50 -0400 Subject: [PATCH 10/37] Update docs/install-upgrade/config.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 5746a25..bb6e090 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -7,7 +7,7 @@ The `fab.yaml` file is the configuration file for the fabric. It supplies the co The fabric yaml object has 4 objects: - `mode` - either `spine-leaf` or `collapsed-core` -- `includeONIE` - defaults to true +- `includeONIE` - defaults to `true` - `defaultSwitchUsers` - the admin and operator credentials for SONiC. - `defaultAlloyConfig` - The configuration details for telemetry of switch information From b0105e0faf557fc22238a77c8a4b07e16cc063e4 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 21:04:04 -0400 Subject: [PATCH 11/37] Update docs/install-upgrade/overview.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index c2df403..f166d93 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -35,7 +35,7 @@ The main steps to install Fabric are: 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and Installer -Hedgehog has created a command line utility, called `hhfab`, that will help generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. +Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` From ca36be03a3c0c54614857be6750af9ac0381a149 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 21:18:34 -0400 Subject: [PATCH 12/37] Apply suggestions from code review Thank for the thorough review! Co-authored-by: Quentin Monnet --- docs/install-upgrade/build-wiring.md | 2 +- docs/install-upgrade/config.md | 5 +++-- docs/install-upgrade/overview.md | 30 ++++++++++++++-------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 9a5d397..09a210f 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -55,7 +55,7 @@ Fabric connections serve as connections between switches, they form the fabric o ### VPC Peering -This is what is needed for VPCs to talk to each other. There are two varieties local and remote. +VPCs need VPC Peerings to talk to each other. VPC Peerings come in two varieties: local and remote. #### Local VPC Peering diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index bb6e090..a00fb1e 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -65,7 +65,8 @@ For additional options, see the `AlloyConfig` [struct in Fabric repo](https://gi ### Configure switch users -It's currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: +Configuring switch users is currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: + ```yaml spec: config: @@ -124,7 +125,7 @@ metadata: spec: config: control: - tlsSAN: # IPs and DNS names that will be used to access API + tlsSAN: # IPs and DNS names to access API - "env-2.l.hhdev.io" defaultUser: # user 'core' on all control nodes diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index f166d93..1ed8efd 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -39,20 +39,21 @@ Hedgehog has created a command line utility, called `hhfab`, that helps generate ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` -1. The `init` command will generate a `fab.yaml` file, edit the `fab.yaml` file for your needs +1. The `init` command generates a `fab.yaml` file, edit the `fab.yaml` file for your needs 1. ensure the correct boot disk (e.g. `/dev/sda`) and control node NIC names are supplied 1. `hhfab validate` 1. `hhfab build` The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img. Once the image is created, it can be written to a USB drive, or mounted via virtual media. -### Write USB image to disk +### Write USB Image to Disk + !!! warning "" - This will erase data on the usb disk. + This will erase data on the USB disk. - Insert the usb to your machine -- Identify the path to your usb stick for example `/dev/sdc` -- Issue the command to write the image to the usb drive +- Identify the path to your USB stick, for example: `/dev/sdc` +- Issue the command to write the image to the USB drive - `sudo dd if=/path/to/control-os/img of=/dev/sdc bs=4k status=progress` There are utilities that assist this process such as [etcher](https://etcher.balena.io/). @@ -68,32 +69,31 @@ This control node should be given a static IP address. Either a lease or statica 1. Select boot off of the attached media, the installation process is **automated** -1. Once the control node has booted it will auto login and begin the installation process - 1. Optionally use ` journalctl -f -u flatcar-install.service` to monitor progress +1. Once the control node has booted, it logs in automatically and begins the installation process + 1. Optionally use `journalctl -f -u flatcar-install.service` to monitor progress -1. Once the install is complete the system will automatically reboot +1. Once the installation is complete, the system automatically reboots. -1. After the system has shutdown but before the boot up process reaches the operating system, **remove the usb image from the system**. Removal this during the uefi boot screen is acceptable. +1. After the system has shutdown but before the boot up process reaches the operating system, **remove the USB image from the system**. Removal during the UEFI boot screen is acceptable. 1. Upon booting into the freshly installed system, the fabric installation will **automatically begin** - 1. If the insecure `--dev` flag was passed to `hhfab init` the password for the `core` user is `HHFab.Admin!`, the switches have two users created `admin` and `op`. `admin` has administrator privileges and password `HHFab.Admin!`, the op user is a read only, non sudo user with password, `HHFab.Op!`. + 1. If the insecure `--dev` flag was passed to `hhfab init` the password for the `core` user is `HHFab.Admin!`, the switches have two users created `admin` and `op`. `admin` has administrator privileges and password `HHFab.Admin!`, whereas the `op` user is a read-only, non-sudo user with password `HHFab.Op!`. 1. Optionally this can be monitored with `journalctl -f -u fabric-install.service` -1. The install is complete when the log emits "Control Node installation complete" - 1. Additionally the systemctl status will show `inactive (dead)` indicating that the executable has finished +1. The install is complete when the log emits "Control Node installation complete". Additionally, the systemctl status will show `inactive (dead)` indicating that the executable has finished. ### Configure Management Network -The control node is dual homed. It has a 10GbE interface that connects to the managment network. The other link called `external` in the `fab.yaml` file is for the customer to access the control node. The management network is for the command and control of the switches that comprise the fabric. This management network can be a simple broadcast domain with layer 2 connectivity. The control node will run a dhcp and small http server. The management network shall not be accessible to machine or devices not associated with the fabric. +The control node is dual-homed. It has a 10GbE interface that connects to the management network. The other link called `external` in the `fab.yaml` file is for the customer to access the control node. The management network is for the command and control of the switches that comprise the fabric. This management network can be a simple broadcast domain with layer 2 connectivity. The control node will run a DHCP and small http servers. The management network is not accessible to machines or devices not associated with the fabric. ### Fabric Manages Switches Now that the install has finished, you can start interacting with the Fabric using `kubectl`, `kubectl fabric` and `k9s`, all pre-installed as part of the Control Node installer. -Now the fabric is handing out dhcp addresses to the switches via the management network. Optionally, to monitor this process: +At this stage, the fabric hands out DHCP addresses to the switches via the management network. Optionally, you can monitor this process by going through the following steps: - enter `k9s` at the command prompt - use the arrow keys to select the boot pod TODO (use the specific name) -- the logs of the pod will be displayed showing the dhcp lease process +- the logs of the pod will be displayed showing the DHCP lease process - use the switches screen of `k9s` to see the heartbeat column to verify the connection between switch and controller. - to see the switches type `:switches` (like a vim command) into `k9s` From b94c3bce303c2425438257c03a64bc5ecc3bfbe2 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 21:37:59 -0400 Subject: [PATCH 13/37] cap YAML --- docs/install-upgrade/config.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index a00fb1e..f20990a 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -1,10 +1,10 @@ # Fabric Configuration ## Overview -The `fab.yaml` file is the configuration file for the fabric. It supplies the configuration of the users, their credentials, logging, telemetry, and other non wiring related settings. The `fab.yaml` file is composed of multiple yaml documents inside of a single file. Per the yamls spec 3 hyphens (`---`) on a single line separate the end of one document from the beginning of the next. There are two yaml documents in the `fab.yaml` file. For more information about how to use `hhfab init`, run `hhfab init --help`. +The `fab.yaml` file is the configuration file for the fabric. It supplies the configuration of the users, their credentials, logging, telemetry, and other non wiring related settings. The `fab.yaml` file is composed of multiple YAML documents inside of a single file. Per the yamls spec 3 hyphens (`---`) on a single line separate the end of one document from the beginning of the next. There are two YAML documents in the `fab.yaml` file. For more information about how to use `hhfab init`, run `hhfab init --help`. ## Fabric -The fabric yaml object has 4 objects: +The fabric YAML object has 4 objects: - `mode` - either `spine-leaf` or `collapsed-core` - `includeONIE` - defaults to `true` @@ -21,7 +21,7 @@ access the configured targets. It could be done by passing `--control-proxy=true Metrics includes port speeds, counters, errors, operational status, transceivers, fans, power supplies, temperature sensors, BGP neighbors, LLDP neighbors, and more. Logs include agent logs. -Configuring the exporters and targets is currently only possible by using a yaml configuration file for the +Configuring the exporters and targets is currently only possible by using a YAML configuration file for the `hhfab init -c ` command using the following format: ```yaml @@ -65,7 +65,7 @@ For additional options, see the `AlloyConfig` [struct in Fabric repo](https://gi ### Configure switch users -Configuring switch users is currently only possible by using a yaml configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: +Configuring switch users is currently only possible by using a YAML configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: ```yaml spec: @@ -95,7 +95,7 @@ spec: The role of the user,`operator` is read-only access to `sonic-cli` command on the switches. In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. ## Control Node -This is the yaml document configure the control node: +This is the YAML document configure the control node: ```yaml apiVersion: fabricator.githedgehog.com/v1beta1 kind: ControlNode From b6d6d74e29f916073b60b8d912d8f2ab48cfd1e7 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 21:38:20 -0400 Subject: [PATCH 14/37] numbers for sequential steps --- docs/install-upgrade/overview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 1ed8efd..8d79f88 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -51,9 +51,9 @@ The installer for the fabric will be generated in `$WORKDIR/result/`. This insta !!! warning "" This will erase data on the USB disk. -- Insert the usb to your machine -- Identify the path to your USB stick, for example: `/dev/sdc` -- Issue the command to write the image to the USB drive +1. Insert the usb to your machine +1. Identify the path to your USB stick, for example: `/dev/sdc` +1. Issue the command to write the image to the USB drive - `sudo dd if=/path/to/control-os/img of=/dev/sdc bs=4k status=progress` There are utilities that assist this process such as [etcher](https://etcher.balena.io/). From f98306ba97dc8c4b0c643924ce7760e17e231122 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 22:28:55 -0400 Subject: [PATCH 15/37] incorporate feedback --- docs/install-upgrade/build-wiring.md | 16 ++++++++-------- docs/install-upgrade/config.md | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 09a210f..183e6cd 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -5,7 +5,7 @@ ## Overview -A wiring diagram is a yaml file that is a digital representation of your network. You can find more yaml level details in the User Guide section [switch features and port naming](../user-guide/profiles.md) and the [api](../reference/api.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. +A wiring diagram is a YAML file that is a digital representation of your network. You can find more YAML level details in the User Guide section [switch features and port naming](../user-guide/profiles.md) and the [api](../reference/api.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. In the meantime, to have a look at working wiring diagram for Hedgehog Fabric, run the sample generator that produces VLAB-compatible wiring diagrams: @@ -33,7 +33,7 @@ This section is meant to help the reader understand how to assemble the primitiv ### VPC -A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC will see each other but nothing else. The hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. +A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC belong to the same broadcast domain and can communicate with each other. The hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. ### Connection @@ -41,12 +41,12 @@ A connection represents the physical wires in your data center. They connect swi #### Server Connections -A server connection will require server side configuration as the Fabric configuration abilities do not reach into the end hosts. A server connection can be one of: +A server connection is a connection used to connect servers to the fabric. The fabric will configure the server-facing port according to the type of the connection (MLAG, Bundle, etc).The configuration of the actual server needs to be done by the server administrator. The server name is not validated by the fabric and is used as metadata to identify the connection. A server connection can be one of: -- *Unbundled* - a single cable going from switch to server -- *Bundled* - two or more cables going to a single switch, the server needs to configured for this, Fabric handles the switch -- *MCLAG* - two cables going to two different switches, also called dual homing. The switches will need a fabric link between them -- *ESLAG* - two to four cables going to different switches, also called multi-homing. If four links are used there will be four switches connected to a single server with four NIC ports +- *Unbundled* - A single cable connecting switch to server. +- *Bundled* - Two or more cables going to a single switch, a LAG or similar. +- *MCLAG* - Two cables going to two different switches, also called dual homing. The switches will need a fabric link between them. +- *ESLAG* - Two to four cables going to different switches, also called multi-homing. If four links are used there will need to be four switches connected to a single server with four NIC ports. #### Fabric Connections @@ -73,4 +73,4 @@ When the VPCs that need to communicate are on different switches. An example wou ### TODO - show how to connect to an AWS cloud connection -### TODO - show how to connect to a provider ISP like equinix +### TODO - show how to connect to a provider ISP like equinix`` diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index f20990a..8847542 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -9,7 +9,7 @@ The fabric YAML object has 4 objects: - `mode` - either `spine-leaf` or `collapsed-core` - `includeONIE` - defaults to `true` - `defaultSwitchUsers` - the admin and operator credentials for SONiC. -- `defaultAlloyConfig` - The configuration details for telemetry of switch information +- `defaultAlloyConfig` - the configuration details for telemetry of switch information ### Forward switch metrics and logs @@ -95,7 +95,7 @@ spec: The role of the user,`operator` is read-only access to `sonic-cli` command on the switches. In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. ## Control Node -This is the YAML document configure the control node: +The control node is the host that manages all the switches, runs k3s, and serves images. This is the YAML document configure the control node: ```yaml apiVersion: fabricator.githedgehog.com/v1beta1 kind: ControlNode @@ -113,7 +113,7 @@ spec: # Currently only one ControlNode is supported ``` -The **management** interface is for the control node to manage the fabric switches, *not* end-user management of the control node. For end user management of the control node specify the **external** interface name. +The **management** interface is for the control node to manage the fabric switches, *not* end-user management of the control node. For end-user management of the control node specify the **external** interface name. ## Complete Example File ```yaml From 8855ae2995c2fe0fafe45d67b4e2cb5a2731cfee Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 22:30:19 -0400 Subject: [PATCH 16/37] Update docs/install-upgrade/overview.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 8d79f88..71512c3 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -44,7 +44,7 @@ Hedgehog has created a command line utility, called `hhfab`, that helps generate 1. `hhfab validate` 1. `hhfab build` -The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img. Once the image is created, it can be written to a USB drive, or mounted via virtual media. +The installer for the fabric is generated in `$WORKDIR/result/`. This installation image is named `control-1-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. ### Write USB Image to Disk From 6a08106a51229f2dc614a9510ec4fa3a877da144 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:25:27 -0400 Subject: [PATCH 17/37] add NTP and DHCP section --- docs/install-upgrade/config.md | 9 ++++++++- docs/install-upgrade/overview.md | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 8847542..057e69a 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -94,6 +94,9 @@ spec: ``` The role of the user,`operator` is read-only access to `sonic-cli` command on the switches. In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. +### NTP and DHCP +The control node uses public ntp servers from cloudflare and google by default. The control node runs a dhcp server on the management network. + ## Control Node The control node is the host that manages all the switches, runs k3s, and serves images. This is the YAML document configure the control node: ```yaml @@ -126,7 +129,11 @@ spec: config: control: tlsSAN: # IPs and DNS names to access API - - "env-2.l.hhdev.io" + - "customer.site.io" + + ntpServers: + - time.cloudflare.com + - time1.google.com defaultUser: # user 'core' on all control nodes password: "hash..." # password hash diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 8d79f88..0e1c61d 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -23,7 +23,7 @@ The main steps to install Fabric are: 1. Install `hhfab` on the machines with access to the Internet 1. [Prepare Wiring Diagram](./build-wiring.md) - 1. [Select Fabric Configuration](./config.md) // TODO - section on dhcp or ntp servers, the FAB.yaml + 1. [Select Fabric Configuration](./config.md) 1. [Build Control Node configuration and installer](#build-control-node-configuration-and-installer) 1. [Install Control Node](#install-control-node) 1. Insert USB with control-os image into Fabric Control Node @@ -93,7 +93,7 @@ Now that the install has finished, you can start interacting with the Fabric usi At this stage, the fabric hands out DHCP addresses to the switches via the management network. Optionally, you can monitor this process by going through the following steps: - enter `k9s` at the command prompt -- use the arrow keys to select the boot pod TODO (use the specific name) +- use the arrow keys to select the pod named `fabric-boot` - the logs of the pod will be displayed showing the DHCP lease process - use the switches screen of `k9s` to see the heartbeat column to verify the connection between switch and controller. - to see the switches type `:switches` (like a vim command) into `k9s` From 8a7aec1c6e7825ebaa3fc1c7db153acd27742e46 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:32:40 -0400 Subject: [PATCH 18/37] remove onie section --- docs/install-upgrade/.pages | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/install-upgrade/.pages b/docs/install-upgrade/.pages index d0238c4..5be4463 100644 --- a/docs/install-upgrade/.pages +++ b/docs/install-upgrade/.pages @@ -4,5 +4,3 @@ nav: - System Requirements: requirements.md - Build Wiring Diagram: build-wiring.md - Fabric Configuration: config.md - - ONIE Update (prepare switch): onie-update.md - - ... From d5b4c117ccbc791b7ea5cd4217db655b5357e6eb Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:33:15 -0400 Subject: [PATCH 19/37] remove Das Boot --- docs/concepts/overview.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/docs/concepts/overview.md b/docs/concepts/overview.md index 8da8b26..5f4fb40 100644 --- a/docs/concepts/overview.md +++ b/docs/concepts/overview.md @@ -12,7 +12,6 @@ Hedgehog Fabric consists of the following components: * Fabricator - special tool to install and configure Fabric, or to run virtual labs * Control Node - one or more Kubernetes nodes in a single cluster running Fabric software: - * Das Boot - set of services providing switch boot and installation * Fabric Controller - main control plane component that manages Fabric resources * Fabric Kubectl plugin (Fabric CLI) - kubectl plugin to manage Fabric resources in an easy way * Fabric Agent - runs on every switch and manages switch configuration @@ -68,24 +67,6 @@ Installer builder and VLAB. * Installation progress, status and retries * Disaster recovery and backups -## Das Boot - -Switch boot and installation. - -* Seeder - * Actual switch provisioning - * ONIE on a switch discovers Control Node using LLDP - * Loads and runs Hedgehog's multi-stage installer - * Network configuration and identity setup - * Performs device registration - * Hedgehog identity partition gets created on the switch - * Downloads SONiC installer and runs it - * Downloads Agent and its config and installs to the switch -* Registration Controller - * Device identity and registration -* Actual SONiC installers -* Miscellaneous: rsyslog/ntp - ## Fabric Control plane and switch agent. From 33b20b8e7c35a63644fc83d01f06e43aba8c76d8 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:51:11 -0400 Subject: [PATCH 20/37] update api version in YAML listing --- docs/user-guide/connections.md | 20 ++++++++++---------- docs/user-guide/devices.md | 16 ++++++++-------- docs/user-guide/external.md | 16 ++++++++-------- docs/user-guide/vpcs.md | 14 +++++++------- docs/vlab/demo.md | 4 ++-- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/user-guide/connections.md b/docs/user-guide/connections.md index 21b0e10..28b60b7 100644 --- a/docs/user-guide/connections.md +++ b/docs/user-guide/connections.md @@ -19,7 +19,7 @@ Server connections are used to connect workload servers to switches. Unbundled server connections are used to connect servers to a single switch using a single port. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-4--unbundled--s5248-02 @@ -38,7 +38,7 @@ spec: Bundled server connections are used to connect servers to a single switch using multiple ports (port channel, LAG). ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-3--bundled--s5248-01 @@ -64,7 +64,7 @@ and a Connection with type `mclag-domain` between them. MCLAG switches should al `spec.VTEPIP`. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-1--mclag--s5248-01--s5248-02 @@ -89,7 +89,7 @@ should belong to the same redundancy group with type `eslag`, but contrary to th required. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-1--eslag--s5248-01--s5248-02 @@ -117,7 +117,7 @@ the Fabric features. A Fabric Connection is used between a specific pair of spine and leaf switches, representing all of the wires between them. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5232-01--fabric--s5248-01 @@ -146,7 +146,7 @@ configured as an MCLAG, pair which requires them to be in a single redundancy gr type `mclag-domain` between them. MCLAG switches should also have the same `spec.ASN` and `spec.VTEPIP`. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-01--mclag-domain--s5248-02 @@ -179,7 +179,7 @@ VPC-Loopback connections are required in order to implement a workaround for the attached to the same switch), which is caused by a hardware limitation of the currently supported switches. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-01--vpc-loopback @@ -202,7 +202,7 @@ spec: Management connections define connections to the Control Node. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: control-1--mgmt--s5248-01-front @@ -229,7 +229,7 @@ Internet, to other networks, or to some other systems such as DHCP, NTP, LMA, or them to specific switch ports. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: third-party-dhcp-server--static-external--s5248-04 @@ -265,7 +265,7 @@ Connection to external systems, such as edge/provider routers using BGP peering communities as well as granularly controlling what gets advertised and which routes are accepted. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-03--external--5835 diff --git a/docs/user-guide/devices.md b/docs/user-guide/devices.md index 7aad39e..db0d810 100644 --- a/docs/user-guide/devices.md +++ b/docs/user-guide/devices.md @@ -12,7 +12,7 @@ IP addresses, and more. Additionally, a `Switch` contains a reference to a `Swit model and capabilities. More details can be found in the [Switch Profiles and Port Naming](./profiles.md) section. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-01 @@ -49,7 +49,7 @@ spec: The `SwitchGroup` is just a marker at that point and doesn't have any configuration options. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: border @@ -75,14 +75,14 @@ switches using the `redundancy` field. Example of switch configured for ESLAG: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: eslag-1 namespace: default spec: {} --- -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-03 @@ -98,14 +98,14 @@ spec: And example of switch configured for MCLAG: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: mclag-1 namespace: default spec: {} --- -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-01 @@ -128,7 +128,7 @@ Servers include both control nodes and user's workload servers. Control Node: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Server metadata: name: control-1 @@ -140,7 +140,7 @@ spec: Regular workload server: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Server metadata: name: server-1 diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index 4d6ca59..ffed6e2 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -57,7 +57,7 @@ with the following configuration: Each `External` should be bound to some VPC IP Namespace, otherwise prefixes overlap may happen. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: External metadata: name: default--5835 @@ -72,7 +72,7 @@ spec: A `Connection` of type `external` is used to identify the switch port on Border leaf that is cabled with an Edge device. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: # specified or generated @@ -90,7 +90,7 @@ bound to a `Connection` with type `external` and they specify an optional `vlan` particular Edge peering. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalAttachment metadata: name: # @@ -113,7 +113,7 @@ To allow a specific VPC to have access to Edge devices, bind the VPC to a specif an `External Peering` object. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalPeering metadata: name: # Name of ExternalPeering @@ -171,7 +171,7 @@ the Border Leaf `switchBorder` that has a cable connecting it to an Edge device ``` ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: External metadata: name: HedgeEdge @@ -190,7 +190,7 @@ Connection should be specified in the `wiring` diagram. ### ### switchBorder--external--HedgeEdge ### -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: switchBorder--external--HedgeEdge @@ -206,7 +206,7 @@ spec: Specified in `wiring` diagram ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalAttachment metadata: name: switchBorder--HedgeEdge @@ -224,7 +224,7 @@ spec: #### ExternalPeering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalPeering metadata: name: vpc-1--HedgeEdge diff --git a/docs/user-guide/vpcs.md b/docs/user-guide/vpcs.md index 7ee2f1f..0cce48b 100644 --- a/docs/user-guide/vpcs.md +++ b/docs/user-guide/vpcs.md @@ -6,7 +6,7 @@ A Virtual Private Cloud (VPC) is similar to a public cloud VPC. It provides an i each with user-defined VLANs and optional DHCP services. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPC metadata: name: vpc-1 @@ -91,7 +91,7 @@ It basically leads to the VPC being available on the specific server port(s) on VPC could be attached to a switch that is part of the VLAN namespace used by the VPC. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCAttachment metadata: name: vpc-1-server-1--mclag--s5248-01--s5248-02 @@ -114,7 +114,7 @@ VPC peering is only possible between VPCs attached to the same IPv4 namespace (s ### Local VPC peering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -128,7 +128,7 @@ spec: ### Remote VPC peering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -146,7 +146,7 @@ It's possible to specify which specific subnets of the peering VPCs could commun field. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -169,7 +169,7 @@ An `IPv4Namespace` defines a set of (non-overlapping) IPv4 address ranges availa Each VPC belongs to a specific IPv4 namespace. Therefore, its subnet prefixes must be from that IPv4 namespace. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: IPv4Namespace metadata: name: default @@ -185,7 +185,7 @@ A `VLANNamespace` defines a set of VLAN ranges available for attaching servers t disjoint VLANNamespaces. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: VLANNamespace metadata: name: default diff --git a/docs/vlab/demo.md b/docs/vlab/demo.md index 4956cb6..d6e5009 100644 --- a/docs/vlab/demo.md +++ b/docs/vlab/demo.md @@ -302,7 +302,7 @@ NAME SUBNETS AGE default ["10.0.0.0/16"] 24m core@control-1 ~ $ cat < ipns-2.yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: IPv4Namespace metadata: name: ipns-2 @@ -327,7 +327,7 @@ Now we can create `vpc-3` with the same subnet as `vpc-1` (but in the different ```console core@control-1 ~ $ cat < vpc-3.yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPC metadata: name: vpc-3 From d108465f7a858688b7b12e3871ddcf723a07e717 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Tue, 22 Oct 2024 22:30:19 -0400 Subject: [PATCH 21/37] Update docs/install-upgrade/overview.md Co-authored-by: Quentin Monnet --- docs/install-upgrade/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 0e1c61d..6009c47 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -44,7 +44,7 @@ Hedgehog has created a command line utility, called `hhfab`, that helps generate 1. `hhfab validate` 1. `hhfab build` -The installer for the fabric will be generated in `$WORKDIR/result/`. This installation image is 7.5 GB in size. It is named control-1-usb.img. Once the image is created, it can be written to a USB drive, or mounted via virtual media. +The installer for the fabric is generated in `$WORKDIR/result/`. This installation image is named `control-1-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. ### Write USB Image to Disk From f6ea6908e0e703dd1a369e98d3b30db802381143 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:32:40 -0400 Subject: [PATCH 22/37] remove onie section --- docs/install-upgrade/.pages | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/install-upgrade/.pages b/docs/install-upgrade/.pages index d0238c4..5be4463 100644 --- a/docs/install-upgrade/.pages +++ b/docs/install-upgrade/.pages @@ -4,5 +4,3 @@ nav: - System Requirements: requirements.md - Build Wiring Diagram: build-wiring.md - Fabric Configuration: config.md - - ONIE Update (prepare switch): onie-update.md - - ... From 096c6f1e5f4ad9b325ae3c95f1404cd2796a1c74 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:33:15 -0400 Subject: [PATCH 23/37] remove Das Boot --- docs/concepts/overview.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/docs/concepts/overview.md b/docs/concepts/overview.md index 8da8b26..5f4fb40 100644 --- a/docs/concepts/overview.md +++ b/docs/concepts/overview.md @@ -12,7 +12,6 @@ Hedgehog Fabric consists of the following components: * Fabricator - special tool to install and configure Fabric, or to run virtual labs * Control Node - one or more Kubernetes nodes in a single cluster running Fabric software: - * Das Boot - set of services providing switch boot and installation * Fabric Controller - main control plane component that manages Fabric resources * Fabric Kubectl plugin (Fabric CLI) - kubectl plugin to manage Fabric resources in an easy way * Fabric Agent - runs on every switch and manages switch configuration @@ -68,24 +67,6 @@ Installer builder and VLAB. * Installation progress, status and retries * Disaster recovery and backups -## Das Boot - -Switch boot and installation. - -* Seeder - * Actual switch provisioning - * ONIE on a switch discovers Control Node using LLDP - * Loads and runs Hedgehog's multi-stage installer - * Network configuration and identity setup - * Performs device registration - * Hedgehog identity partition gets created on the switch - * Downloads SONiC installer and runs it - * Downloads Agent and its config and installs to the switch -* Registration Controller - * Device identity and registration -* Actual SONiC installers -* Miscellaneous: rsyslog/ntp - ## Fabric Control plane and switch agent. From dc8b54ff990c94c77307ed3db96b3d5222551fd7 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 10:51:11 -0400 Subject: [PATCH 24/37] update api version in YAML listing --- docs/user-guide/connections.md | 20 ++++++++++---------- docs/user-guide/devices.md | 16 ++++++++-------- docs/user-guide/external.md | 16 ++++++++-------- docs/user-guide/vpcs.md | 14 +++++++------- docs/vlab/demo.md | 4 ++-- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/user-guide/connections.md b/docs/user-guide/connections.md index 21b0e10..28b60b7 100644 --- a/docs/user-guide/connections.md +++ b/docs/user-guide/connections.md @@ -19,7 +19,7 @@ Server connections are used to connect workload servers to switches. Unbundled server connections are used to connect servers to a single switch using a single port. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-4--unbundled--s5248-02 @@ -38,7 +38,7 @@ spec: Bundled server connections are used to connect servers to a single switch using multiple ports (port channel, LAG). ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-3--bundled--s5248-01 @@ -64,7 +64,7 @@ and a Connection with type `mclag-domain` between them. MCLAG switches should al `spec.VTEPIP`. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-1--mclag--s5248-01--s5248-02 @@ -89,7 +89,7 @@ should belong to the same redundancy group with type `eslag`, but contrary to th required. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: server-1--eslag--s5248-01--s5248-02 @@ -117,7 +117,7 @@ the Fabric features. A Fabric Connection is used between a specific pair of spine and leaf switches, representing all of the wires between them. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5232-01--fabric--s5248-01 @@ -146,7 +146,7 @@ configured as an MCLAG, pair which requires them to be in a single redundancy gr type `mclag-domain` between them. MCLAG switches should also have the same `spec.ASN` and `spec.VTEPIP`. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-01--mclag-domain--s5248-02 @@ -179,7 +179,7 @@ VPC-Loopback connections are required in order to implement a workaround for the attached to the same switch), which is caused by a hardware limitation of the currently supported switches. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-01--vpc-loopback @@ -202,7 +202,7 @@ spec: Management connections define connections to the Control Node. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: control-1--mgmt--s5248-01-front @@ -229,7 +229,7 @@ Internet, to other networks, or to some other systems such as DHCP, NTP, LMA, or them to specific switch ports. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: third-party-dhcp-server--static-external--s5248-04 @@ -265,7 +265,7 @@ Connection to external systems, such as edge/provider routers using BGP peering communities as well as granularly controlling what gets advertised and which routes are accepted. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: s5248-03--external--5835 diff --git a/docs/user-guide/devices.md b/docs/user-guide/devices.md index 7aad39e..db0d810 100644 --- a/docs/user-guide/devices.md +++ b/docs/user-guide/devices.md @@ -12,7 +12,7 @@ IP addresses, and more. Additionally, a `Switch` contains a reference to a `Swit model and capabilities. More details can be found in the [Switch Profiles and Port Naming](./profiles.md) section. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-01 @@ -49,7 +49,7 @@ spec: The `SwitchGroup` is just a marker at that point and doesn't have any configuration options. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: border @@ -75,14 +75,14 @@ switches using the `redundancy` field. Example of switch configured for ESLAG: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: eslag-1 namespace: default spec: {} --- -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-03 @@ -98,14 +98,14 @@ spec: And example of switch configured for MCLAG: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: SwitchGroup metadata: name: mclag-1 namespace: default spec: {} --- -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch metadata: name: s5248-01 @@ -128,7 +128,7 @@ Servers include both control nodes and user's workload servers. Control Node: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Server metadata: name: control-1 @@ -140,7 +140,7 @@ spec: Regular workload server: ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Server metadata: name: server-1 diff --git a/docs/user-guide/external.md b/docs/user-guide/external.md index 4d6ca59..ffed6e2 100644 --- a/docs/user-guide/external.md +++ b/docs/user-guide/external.md @@ -57,7 +57,7 @@ with the following configuration: Each `External` should be bound to some VPC IP Namespace, otherwise prefixes overlap may happen. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: External metadata: name: default--5835 @@ -72,7 +72,7 @@ spec: A `Connection` of type `external` is used to identify the switch port on Border leaf that is cabled with an Edge device. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: # specified or generated @@ -90,7 +90,7 @@ bound to a `Connection` with type `external` and they specify an optional `vlan` particular Edge peering. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalAttachment metadata: name: # @@ -113,7 +113,7 @@ To allow a specific VPC to have access to Edge devices, bind the VPC to a specif an `External Peering` object. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalPeering metadata: name: # Name of ExternalPeering @@ -171,7 +171,7 @@ the Border Leaf `switchBorder` that has a cable connecting it to an Edge device ``` ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: External metadata: name: HedgeEdge @@ -190,7 +190,7 @@ Connection should be specified in the `wiring` diagram. ### ### switchBorder--external--HedgeEdge ### -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: Connection metadata: name: switchBorder--external--HedgeEdge @@ -206,7 +206,7 @@ spec: Specified in `wiring` diagram ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalAttachment metadata: name: switchBorder--HedgeEdge @@ -224,7 +224,7 @@ spec: #### ExternalPeering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: ExternalPeering metadata: name: vpc-1--HedgeEdge diff --git a/docs/user-guide/vpcs.md b/docs/user-guide/vpcs.md index 7ee2f1f..0cce48b 100644 --- a/docs/user-guide/vpcs.md +++ b/docs/user-guide/vpcs.md @@ -6,7 +6,7 @@ A Virtual Private Cloud (VPC) is similar to a public cloud VPC. It provides an i each with user-defined VLANs and optional DHCP services. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPC metadata: name: vpc-1 @@ -91,7 +91,7 @@ It basically leads to the VPC being available on the specific server port(s) on VPC could be attached to a switch that is part of the VLAN namespace used by the VPC. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCAttachment metadata: name: vpc-1-server-1--mclag--s5248-01--s5248-02 @@ -114,7 +114,7 @@ VPC peering is only possible between VPCs attached to the same IPv4 namespace (s ### Local VPC peering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -128,7 +128,7 @@ spec: ### Remote VPC peering ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -146,7 +146,7 @@ It's possible to specify which specific subnets of the peering VPCs could commun field. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPCPeering metadata: name: vpc-1--vpc-2 @@ -169,7 +169,7 @@ An `IPv4Namespace` defines a set of (non-overlapping) IPv4 address ranges availa Each VPC belongs to a specific IPv4 namespace. Therefore, its subnet prefixes must be from that IPv4 namespace. ```yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: IPv4Namespace metadata: name: default @@ -185,7 +185,7 @@ A `VLANNamespace` defines a set of VLAN ranges available for attaching servers t disjoint VLANNamespaces. ```yaml -apiVersion: wiring.githedgehog.com/v1alpha2 +apiVersion: wiring.githedgehog.com/v1beta1 kind: VLANNamespace metadata: name: default diff --git a/docs/vlab/demo.md b/docs/vlab/demo.md index 4956cb6..d6e5009 100644 --- a/docs/vlab/demo.md +++ b/docs/vlab/demo.md @@ -302,7 +302,7 @@ NAME SUBNETS AGE default ["10.0.0.0/16"] 24m core@control-1 ~ $ cat < ipns-2.yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: IPv4Namespace metadata: name: ipns-2 @@ -327,7 +327,7 @@ Now we can create `vpc-3` with the same subnet as `vpc-1` (but in the different ```console core@control-1 ~ $ cat < vpc-3.yaml -apiVersion: vpc.githedgehog.com/v1alpha2 +apiVersion: vpc.githedgehog.com/v1beta1 kind: VPC metadata: name: vpc-3 From 071a1bbed50e4b246b51c6a112c20b14f079be62 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 12:02:05 -0400 Subject: [PATCH 25/37] add comments from Amit --- docs/install-upgrade/build-wiring.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 183e6cd..d4a5f6b 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -59,18 +59,14 @@ VPCs need VPC Peerings to talk to each other. VPC Peerings come in two varieties #### Local VPC Peering -When the VPCs that need to communicate are both on the same switch. An example would be if your database and web front end servers are in the same rack and are able to be physically cabled to the same switch. +When there is no dedicated border/peering switch available in the fabric we can use local VPC peering. This kind of peering tries to send traffic between the two VPC's on the switch where either of the VPC's has workloads attached. Due to limitation in the Sonic network operating system this kind of peering bandwidth is limited to the number of VPC loopbacks you have selected while initializing the fabric. #### Remote VPC Peering -When the VPCs that need to communicate are on different switches. An example would be if your storage and compute servers are in opposite ends of the data center and need to be cabled to different switches. +Remote Peering is used when you need a high bandwidth connection between the VPCs, you will dedicate a switch to the peering traffic. This is either done on the border leaf or on a switch where either of the VPC's are not present. This kind of peering allows peer traffic between different VPC's at line rate and is only limited by fabric bandwidth. Remote peering introduces a few additional hops in the traffic and may cause a small increase in latency. +#### VPC Loopback -## Design Examples +A VPC loopback is a physical cable with both ends plugged into the same switch, suggested but not required to be the adjacent ports. This loopback allows two different VPCs to communicate with each other. -### TODO - show the wiring diagram for a leaf-spine - -### TODO - show how to connect to an AWS cloud connection - -### TODO - show how to connect to a provider ISP like equinix`` From be682121424f6b055a25735fbae3f08e3b46e3d2 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 15:27:41 -0400 Subject: [PATCH 26/37] remove references to mangement connections as applied to fabric links --- docs/install-upgrade/overview.md | 4 ++-- docs/reference/api.md | 1 - docs/user-guide/connections.md | 21 --------------------- docs/user-guide/profiles.md | 3 --- docs/user-guide/shrink-expand.md | 12 +++++------- docs/vlab/running.md | 5 ----- 6 files changed, 7 insertions(+), 39 deletions(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 6009c47..c721122 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -44,7 +44,7 @@ Hedgehog has created a command line utility, called `hhfab`, that helps generate 1. `hhfab validate` 1. `hhfab build` -The installer for the fabric is generated in `$WORKDIR/result/`. This installation image is named `control-1-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. +The installer for the fabric is generated in `$WORKDIR/result/`. This installation image is named `control-1-install-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. ### Write USB Image to Disk @@ -54,7 +54,7 @@ The installer for the fabric is generated in `$WORKDIR/result/`. This installati 1. Insert the usb to your machine 1. Identify the path to your USB stick, for example: `/dev/sdc` 1. Issue the command to write the image to the USB drive - - `sudo dd if=/path/to/control-os/img of=/dev/sdc bs=4k status=progress` + - `sudo dd if=control-1-install-usb.img of=/dev/sdc bs=4k status=progress` There are utilities that assist this process such as [etcher](https://etcher.balena.io/). diff --git a/docs/reference/api.md b/docs/reference/api.md index 7a79cfe..fcbe7b0 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -1870,7 +1870,6 @@ _Appears in:_ | `label` _string_ | Label defines the physical port label you can see on the actual switch | | | | `group` _string_ | If port isn't directly manageable, group defines the group it belongs to, exclusive with profile | | | | `profile` _string_ | If port is directly configurable, profile defines the profile it belongs to, exclusive with group | | | -| `management` _boolean_ | Management defines if port is a management port, it's a special case and it can't have a group or profile | | | | `oniePortName` _string_ | OniePortName defines the ONIE port name for management ports only | | | diff --git a/docs/user-guide/connections.md b/docs/user-guide/connections.md index 28b60b7..86f664e 100644 --- a/docs/user-guide/connections.md +++ b/docs/user-guide/connections.md @@ -197,27 +197,6 @@ spec: port: s5248-01/Ethernet19 ``` -## Management - -Management connections define connections to the Control Node. - -```yaml -apiVersion: wiring.githedgehog.com/v1beta1 -kind: Connection -metadata: - name: control-1--mgmt--s5248-01-front - namespace: default -spec: - management: - link: # Defines a single link between a control node and a switch - server: - ip: 172.30.20.0/31 - port: control-1/enp2s1 - switch: - ip: 172.30.20.1/31 - port: s5248-01/Ethernet0 -``` - ## Connecting Fabric to the outside world Connections in this section provide connectivity to the outside world. For example, they can be connections to the diff --git a/docs/user-guide/profiles.md b/docs/user-guide/profiles.md index 3cc4f2c..9908c2f 100644 --- a/docs/user-guide/profiles.md +++ b/docs/user-guide/profiles.md @@ -81,6 +81,3 @@ the example above. Omitting the breakout number is allowed for the first breakou `E1/55/1`. The breakout ports are always consecutive numbers independent of the lanes allocation and other implementation details. -### Management ports - -Not configurable, no port profile, only used for connecting the switch to the control node. diff --git a/docs/user-guide/shrink-expand.md b/docs/user-guide/shrink-expand.md index da86499..4ec0008 100644 --- a/docs/user-guide/shrink-expand.md +++ b/docs/user-guide/shrink-expand.md @@ -3,7 +3,7 @@ This section provides a brief overview of how to add or remove switches within the fabric using Hedgehog Fabric API, and how to manage connections between them. -Manipulating API objects is done with the assumption that target devices are correctly cabeled and connected. +Manipulating API objects is done with the assumption that target devices are correctly cabled and connected. This article uses terms that can be found in the [Hedgehog Concepts](../concepts/overview.md), the [User Guide](overview.md) documentation, and the [Fabric API](../reference/api.md) reference. @@ -11,7 +11,7 @@ Guide](overview.md) documentation, and the [Fabric API](../reference/api.md) ref ### Add a switch to the existing fabric In order to be added to the Hedgehog Fabric, a switch should have a corresponding `Switch` object. An example on how to define -this object is available in the [User Guilde](devices.md). +this object is available in the [User Guild](devices.md). !!! note If the`Switch` will be used in `ESLAG` or `MCLAG` groups, appropriate groups should exist. Redundancy groups should @@ -22,13 +22,11 @@ connections may differ based on the `Switch` role given to the device. For more section](connections.md). !!! note - If the switch is facing a Control Node Connection on the front-panel port, the switch port should be described in a - `Management` connection. - -!!! note - Switch devices should be booted in `ONIE` or `HONIE` installation mode to install SONiC OS and configure the Fabric + Switch devices should be booted in `ONIE` installation mode to install SONiC OS and configure the Fabric Agent. +Ensure the management port of the switch is connected to fabric management network. + ### Remove a switch from the existing fabric Before you decommission a switch from the Hedgehog Fabric, several preparation steps are necessary. diff --git a/docs/vlab/running.md b/docs/vlab/running.md index 8fdfb9c..85e0151 100644 --- a/docs/vlab/running.md +++ b/docs/vlab/running.md @@ -282,11 +282,6 @@ For connections, use: ```console core@control-1 ~ $ kubectl get connection NAME TYPE AGE -control-1--mgmt--leaf-01 management 6h11m -control-1--mgmt--leaf-02 management 6h11m -control-1--mgmt--leaf-03 management 6h11m -control-1--mgmt--spine-01 management 6h11m -control-1--mgmt--spine-02 management 6h11m leaf-01--mclag-domain--leaf-02 mclag-domain 6h11m leaf-01--vpc-loopback vpc-loopback 6h11m leaf-02--vpc-loopback vpc-loopback 6h11m From 2b58400e80e4248981e1166c6efa7df9fc60b9d1 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 15:52:55 -0400 Subject: [PATCH 27/37] remove telemetry forwarding --- docs/install-upgrade/config.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 057e69a..2a3e924 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -32,8 +32,6 @@ spec: agentScrapeIntervalSeconds: 120 unixScrapeIntervalSeconds: 120 unixExporterEnabled: true - controlProxy: true # (optional) same as passing --control-proxy=true to hhfab init - controlProxyURL: http://172.30.1.1:31028 lokiTargets: grafana_cloud: # target name, multiple targets can be configured basicAuth: # optional From 6fcf8bf1cb87fd6cd62f765ad7835c0aef78f336 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 16:13:25 -0400 Subject: [PATCH 28/37] add info about management network --- docs/install-upgrade/overview.md | 4 ++-- docs/install-upgrade/requirements.md | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index c721122..38cfb44 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -29,8 +29,8 @@ The main steps to install Fabric are: 1. Insert USB with control-os image into Fabric Control Node 1. Boot the node off the USB to initiate the installation 1. Prepare Management Network - 1. Connect switch to Fabric control node - 1. Connect 1GbE Management ports of switches to control switch + 1. Connect management switch to Fabric control node + 1. Connect 1GbE Management port of switches to management switch 1. Prepare supported switches 1. Boot them into ONIE Install Mode to have them automatically provisioned diff --git a/docs/install-upgrade/requirements.md b/docs/install-upgrade/requirements.md index e0b2b73..edc0b78 100644 --- a/docs/install-upgrade/requirements.md +++ b/docs/install-upgrade/requirements.md @@ -1,5 +1,6 @@ # System Requirements +## Control Node - Fast SSDs for system/root as well as Kubernetes and container runtime folders are required for stable work - SSDs are mandatory for Control Nodes - 10 GbE port for connection to management network @@ -7,6 +8,12 @@ - (Future) Full (HA) setup is at least 3 Control Nodes - (Future) Extra nodes could be used for things like Logging, Monitoring, Alerting stack, and more + +## Out of Band Management Network + +In order to provision and manage the switches that comprise the fabric, an out of band switch must also be installed. This network is to be used exclusively by the control node and the fabric switches, no other access is permitted. This switch is not manged by the fabric. It is recommended that this switch have at least a 10GbE port and that port connect to the control node. + + ## Non-HA (minimal) setup - 1 Control Node - Control Node runs non-HA Kubernetes Control Plane installation with non-HA Hedgehog Fabric Control Plane on top of it From 74c1f62bd236a3c0cc3a85223cd1c6821ea54f50 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 16:16:13 -0400 Subject: [PATCH 29/37] unneeded whitespace --- docs/reference/api.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/reference/api.md b/docs/reference/api.md index fcbe7b0..fb84089 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -38,8 +38,6 @@ _Appears in:_ #### Agent - - Agent is an internal API object used by the controller to pass all relevant information to the agent running on a specific switch in order to fully configure it and manage its lifecycle. It is not intended to be used directly by users. Spec of the object isn't user-editable, it is managed by the controller. Status of the object is updated by From b3ebc3a13c8793936e779f02086fd9a7a2b56be2 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 16:19:00 -0400 Subject: [PATCH 30/37] remove switch, remove control node from fabric discussion --- docs/user-guide/devices.md | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/docs/user-guide/devices.md b/docs/user-guide/devices.md index db0d810..490b193 100644 --- a/docs/user-guide/devices.md +++ b/docs/user-guide/devices.md @@ -7,7 +7,7 @@ roles in the Wiring Diagram, together with `Connection` objects (see [Connection ## Switches Switches are the main building blocks of the Fabric. They are represented by `Switch` objects in the API. These objects -consist of basic metadata like name, description, location, role, as well as port group speeds, port breakouts, ASN, +consist of basic metadata like name, description, role, as well as port group speeds, port breakouts, ASN, IP addresses, and more. Additionally, a `Switch` contains a reference to a `SwitchProfile` object that defines the switch model and capabilities. More details can be found in the [Switch Profiles and Port Naming](./profiles.md) section. @@ -22,11 +22,6 @@ spec: asn: 65101 # ASN of the switch description: leaf-1 ip: 172.30.10.100/32 # Switch IP that will be accessible from the Control Node - location: - location: gen--default--s5248-01 - locationSig: - sig: - uuidSig: portBreakouts: # Configures port breakouts for the switch, see the SwitchProfile for available options E1/55: 4x25G portGroupSpeeds: # Configures port group speeds for the switch, see the SwitchProfile for available options @@ -123,20 +118,6 @@ links between switches. For more details, see [Connections](./connections.md). ## Servers -Servers include both control nodes and user's workload servers. - -Control Node: - -```yaml -apiVersion: wiring.githedgehog.com/v1beta1 -kind: Server -metadata: - name: control-1 - namespace: default -spec: - type: control # Type of the server, one of control or "" (empty) for regular workload server -``` - Regular workload server: ```yaml From 0d72410a47d120d1506126ed432c91d91d2f0d23 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 17:26:06 -0400 Subject: [PATCH 31/37] add info about switch serial number / mac address to documentaion --- docs/install-upgrade/overview.md | 1 + docs/user-guide/devices.md | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index 38cfb44..b187e46 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -32,6 +32,7 @@ The main steps to install Fabric are: 1. Connect management switch to Fabric control node 1. Connect 1GbE Management port of switches to management switch 1. Prepare supported switches + 1. Ensure switch serial numbers and / or management interface mac addresses are recorded in wiring diagram 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and Installer diff --git a/docs/user-guide/devices.md b/docs/user-guide/devices.md index 490b193..799e10d 100644 --- a/docs/user-guide/devices.md +++ b/docs/user-guide/devices.md @@ -7,10 +7,12 @@ roles in the Wiring Diagram, together with `Connection` objects (see [Connection ## Switches Switches are the main building blocks of the Fabric. They are represented by `Switch` objects in the API. These objects -consist of basic metadata like name, description, role, as well as port group speeds, port breakouts, ASN, +consist of basic metadata like name, description, role, serial, management port mac, as well as port group speeds, port breakouts, ASN, IP addresses, and more. Additionally, a `Switch` contains a reference to a `SwitchProfile` object that defines the switch model and capabilities. More details can be found in the [Switch Profiles and Port Naming](./profiles.md) section. +In order for the fabric to manage a switch the profile needs to include either the `serial` or `mac` need to be defined in the YAML doc. + ```yaml apiVersion: wiring.githedgehog.com/v1beta1 kind: Switch @@ -18,6 +20,8 @@ metadata: name: s5248-01 namespace: default spec: + boot: + serial: XYZPDQ1234 profile: dell-s5248f-on # Mandatory reference to the SwitchProfile object defining the switch model and capabilities asn: 65101 # ASN of the switch description: leaf-1 From f1ddc6666c54141ab598a5c673496a3abfcc42a1 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 21:15:10 -0400 Subject: [PATCH 32/37] tweaks for hardware install --- docs/install-upgrade/overview.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index b187e46..fde2f4f 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -36,7 +36,8 @@ The main steps to install Fabric are: 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and Installer -Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. +Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram and fabric configuration, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. + ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` @@ -45,14 +46,14 @@ Hedgehog has created a command line utility, called `hhfab`, that helps generate 1. `hhfab validate` 1. `hhfab build` -The installer for the fabric is generated in `$WORKDIR/result/`. This installation image is named `control-1-install-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. +The installer for the fabric is generated in `$CWD/result/`. This installation image is named `control-1-install-usb.img` and is 7.5 GB in size. Once the image is created, you can write it to a USB drive, or mount it via virtual media. ### Write USB Image to Disk !!! warning "" This will erase data on the USB disk. -1. Insert the usb to your machine +1. Insert the USB to your machine 1. Identify the path to your USB stick, for example: `/dev/sdc` 1. Issue the command to write the image to the USB drive - `sudo dd if=control-1-install-usb.img of=/dev/sdc bs=4k status=progress` From 3a93be7e07c0e3071599b7b02043f3c8ac2f69a7 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 22:06:17 -0400 Subject: [PATCH 33/37] updated examples and commands for new hhfab --- docs/vlab/demo.md | 4 +- docs/vlab/running.md | 227 +++++++++++++++++-------------------------- 2 files changed, 90 insertions(+), 141 deletions(-) diff --git a/docs/vlab/demo.md b/docs/vlab/demo.md index d6e5009..64d727c 100644 --- a/docs/vlab/demo.md +++ b/docs/vlab/demo.md @@ -1,5 +1,7 @@ # Demo on VLAB +## Goals + The goal of this demo is to show how to use VPCs, attach and peer them and run test connectivity between the servers. Examples are based on the default VLAB topology. @@ -142,7 +144,7 @@ You can use `hhfab vlab ssh` on the host to SSH into the test servers and config both `server-01` (MCLAG attached to both `leaf-01` and `leaf-02`) we need to configure a bond with a VLAN on top of it and for the `server-05` (single-homed unbundled attached to `leaf-03`) we need to configure just a VLAN and they both will get an IP address from the DHCP server. You can use the `ip` command to configure networking on the servers or use -the little helper preinstalled by Fabricator on test servers, `hhnet`. +the little helper pre-installed by Fabricator on test servers, `hhnet`. For `server-01`: diff --git a/docs/vlab/running.md b/docs/vlab/running.md index 85e0151..e8b9a0b 100644 --- a/docs/vlab/running.md +++ b/docs/vlab/running.md @@ -5,53 +5,59 @@ before running VLAB. ## Initialize VLAB -First, initialize Fabricator for the VLAB by running `hhfab init --preset vlab` (or `-p vlab`). This command supports -several customization options that are listed in the output of `hhfab init --help`. To tune the topology used for the -VLAB, you can use the `--fabric-mode` (or `-m`) flag to choose between `spine-leaf` (default) and `collapsed-core` -topologies. You can also configure the number of spines, leafs, connections, and so on. For example, flags -`--spines-count` and `--mclag-leafs-count` allow you to set the number of spines and MCLAG leaves, respectively. +First, initialize Fabricator by running `hhfab init --dev`. This command supports several customization options that are listed in the output of `hhfab init --help`. -By default, the command creates 2 spines, 2 MCLAG leaves and 1 non-MCLAG leaf with 2 fabric connections (between each -spine and leaf), 2 MCLAG peer links and 2 MCLAG session links as well as 2 loopbacks per leaf for implementing VPC -Loopback workaround. +```console +ubuntu@docs:~$ hhfab init --dev +11:26:52 INF Hedgehog Fabricator version=v0.30.0 +11:26:52 INF Generated initial config +11:26:52 INF Adjust configs (incl. credentials, modes, subnets, etc.) file=fab.yaml +11:26:52 INF Include wiring files (.yaml) or adjust imported ones dir=include +``` +## VLAB Topology + +By default, the command creates 2 spines, 2 MCLAG leaves and 1 non-MCLAG leaf with 2 fabric connections (between each spine and leaf), 2 MCLAG peer links and 2 MCLAG session links as well as 2 loopbacks per leaf for implementing VPC loopback workaround. To generate the preceding topology, `hhfab vlab gen`. You can also configure the number of spines, leafs, connections, and so on. For example, flags `--spines-count` and `--mclag-leafs-count` allow you to set the number of spines and MCLAG leaves, respectively. For complete options, `hhfab vlab gen -h`. ```console -ubuntu@docs:~$ hhfab init -p vlab -01:17:44 INF Generating wiring from gen flags -01:17:44 INF Building wiring diagram fabricMode=spine-leaf chainControlLink=false controlLinksCount=0 -01:17:44 INF >>> spinesCount=2 fabricLinksCount=2 -01:17:44 INF >>> mclagLeafsCount=2 orphanLeafsCount=1 -01:17:44 INF >>> mclagSessionLinks=2 mclagPeerLinks=2 -01:17:44 INF >>> vpcLoopbacks=2 -01:17:44 WRN Wiring is not hydrated, hydrating reason="error validating wiring: ASN not set for switch leaf-01" -01:17:44 INF Initialized preset=vlab fabricMode=spine-leaf config=.hhfab/config.yaml wiring=.hhfab/wiring.yaml +ubuntu@docs:~$ hhfab vlab gen +21:27:16 INF Hedgehog Fabricator version=v0.30.0 +21:27:16 INF Building VLAB wiring diagram fabricMode=spine-leaf +21:27:16 INF >>> spinesCount=2 fabricLinksCount=2 +21:27:16 INF >>> eslagLeafGroups=2 +21:27:16 INF >>> mclagLeafsCount=2 mclagSessionLinks=2 mclagPeerLinks=2 +21:27:16 INF >>> orphanLeafsCount=1 vpcLoopbacks=2 +21:27:16 INF >>> mclagServers=2 eslagServers=2 unbundledServers=1 bundledServers=1 +21:27:16 INF Generated wiring file name=vlab.generated.yaml ``` +### Collapsed Core +If a Collapsed Core topology is desired, after the `hhfab init --dev` step, edit the resulting `fab.yaml` file and change the `mode: spine-leaf` to `mode: collapsed-core`. Or if you want to run Collapsed Core topology with 2 MCLAG switches: ```console -ubuntu@docs:~$ hhfab init -p vlab -m collapsed-core -01:20:07 INF Generating wiring from gen flags -01:20:07 INF Building wiring diagram fabricMode=collapsed-core chainControlLink=false controlLinksCount=0 -01:20:07 INF >>> mclagLeafsCount=2 orphanLeafsCount=0 -01:20:07 INF >>> mclagSessionLinks=2 mclagPeerLinks=2 -01:20:07 INF >>> vpcLoopbacks=2 -01:20:07 WRN Wiring is not hydrated, hydrating reason="error validating wiring: ASN not set for switch leaf-01" -01:20:07 INF Initialized preset=vlab fabricMode=collapsed-core config=.hhfab/config.yaml wiring=.hhfab/wiring.yaml +ubuntu@docs:~$ hhfab vlab gen +11:39:02 INF Hedgehog Fabricator version=v0.30.0 +11:39:02 INF Building VLAB wiring diagram fabricMode=collapsed-core +11:39:02 INF >>> mclagLeafsCount=2 mclagSessionLinks=2 mclagPeerLinks=2 +11:39:02 INF >>> orphanLeafsCount=0 vpcLoopbacks=2 +11:39:02 INF >>> mclagServers=2 eslagServers=2 unbundledServers=1 bundledServers=1 +11:39:02 INF Generated wiring file name=vlab.generated.yaml + ``` +### Custom Spine Leaf Or you can run custom topology with 2 spines, 4 MCLAG leaves and 2 non-MCLAG leaves using flags: ```console -ubuntu@docs:~$ hhfab init -p vlab --mclag-leafs-count 4 --orphan-leafs-count 2 -01:21:53 INF Generating wiring from gen flags -01:21:53 INF Building wiring diagram fabricMode=spine-leaf chainControlLink=false controlLinksCount=0 -01:21:53 INF >>> spinesCount=2 fabricLinksCount=2 -01:21:53 INF >>> mclagLeafsCount=4 orphanLeafsCount=2 -01:21:53 INF >>> mclagSessionLinks=2 mclagPeerLinks=2 -01:21:53 INF >>> vpcLoopbacks=2 -01:21:53 WRN Wiring is not hydrated, hydrating reason="error validating wiring: ASN not set for switch leaf-01" -01:21:53 INF Initialized preset=vlab fabricMode=spine-leaf config=.hhfab/config.yaml wiring=.hhfab/wiring.yaml +ubuntu@docs:~$ hhfab vlab gen --mclag-leafs-count 4 --orphan-leafs-count 2 +11:41:06 INF Hedgehog Fabricator version=v0.30.0 +11:41:06 INF Building VLAB wiring diagram fabricMode=spine-leaf +11:41:06 INF >>> spinesCount=2 fabricLinksCount=2 +11:41:06 INF >>> eslagLeafGroups="" +11:41:06 INF >>> mclagLeafsCount=4 mclagSessionLinks=2 mclagPeerLinks=2 +11:41:06 INF >>> orphanLeafsCount=2 vpcLoopbacks=2 +11:41:06 INF >>> mclagServers=2 eslagServers=2 unbundledServers=1 bundledServers=1 +11:41:06 INF Generated wiring file name=vlab.generated.yaml ``` Additionally, you can pass extra Fabric configuration items using flags on `init` command or by passing a configuration @@ -61,112 +67,57 @@ Once you have initialized the VLAB, download the artifacts and build the install automatically downloads all required artifacts from the OCI registry and builds the installer and all other prerequisites for running the VLAB. -## Build the installer and VLAB - -```console -ubuntu@docs:~$ hhfab build -01:23:33 INF Building component=base -01:23:33 WRN Attention! Development mode enabled - this is not secure! Default users and keys will be created. -... -01:23:33 INF Building component=control-os -01:23:33 INF Building component=k3s -01:23:33 INF Downloading name=m.l.hhdev.io:31000/githedgehog/k3s:v1.27.4-k3s1 to=.hhfab/control-install -Copying k3s-airgap-images-amd64.tar.gz 187.36 MiB / 187.36 MiB ⠙ 0.00 b/s done -Copying k3s 56.50 MiB / 56.50 MiB ⠙ 0.00 b/s done -01:23:35 INF Building component=zot -01:23:35 INF Downloading name=m.l.hhdev.io:31000/githedgehog/zot:v1.4.3 to=.hhfab/control-install -Copying zot-airgap-images-amd64.tar.gz 19.24 MiB / 19.24 MiB ⠸ 0.00 b/s done -01:23:35 INF Building component=misc -01:23:35 INF Downloading name=m.l.hhdev.io:31000/githedgehog/fabricator/k9s:v0.27.4 to=.hhfab/control-install -Copying k9s 57.75 MiB / 57.75 MiB ⠼ 0.00 b/s done -... -01:25:40 INF Planned bundle=control-install name=fabric-api-chart op="push fabric/charts/fabric-api:v0.23.0" -01:25:40 INF Planned bundle=control-install name=fabric-image op="push fabric/fabric:v0.23.0" -01:25:40 INF Planned bundle=control-install name=fabric-chart op="push fabric/charts/fabric:v0.23.0" -01:25:40 INF Planned bundle=control-install name=fabric-agent-seeder op="push fabric/agent/x86_64:latest" -01:25:40 INF Planned bundle=control-install name=fabric-agent op="push fabric/agent:v0.23.0" -... -01:25:40 INF Recipe created bundle=control-install actions=67 -01:25:40 INF Creating recipe bundle=server-install -01:25:40 INF Planned bundle=server-install name=toolbox op="file /opt/hedgehog/toolbox.tar" -01:25:40 INF Planned bundle=server-install name=toolbox-load op="exec ctr" -01:25:40 INF Planned bundle=server-install name=hhnet op="file /opt/bin/hhnet" -01:25:40 INF Recipe created bundle=server-install actions=3 -01:25:40 INF Building done took=2m6.813384532s -01:25:40 INF Packing bundle=control-install target=control-install.tgz -01:25:45 INF Packing bundle=server-install target=server-install.tgz -01:25:45 INF Packing done took=5.67007384s -``` - -As soon as the build has completed, you can run the VLAB using `hhfab vlab up`. This command automatically starts all -VMs and runs the installers on the control node and test servers. It takes some time for all VMs to come up and for the -installer to finish. You can monitor progress in the output. If you stop the command, it will stop all VMs, and you can -re-run it to get VMs back up and running. - -## Run VMs and installers +## Build the Installer and Start VLAB +In VLAB the build and run step are combined into one command for simplicity, `hhfab vlab up`. For successive runs use the `--kill-stale` flag to ensure that any virtual machines from a previous run are gone. This command does not return, it runs as long as the VLAB is up. This is done so that shutdown is a simple `ctrl + c`. ```console ubuntu@docs:~$ hhfab vlab up -01:29:13 INF Starting VLAB server... basedir=.hhfab/vlab-vms vm-size="" dry-run=false -01:29:13 INF VM id=0 name=control-1 type=control -01:29:13 INF VM id=1 name=server-01 type=server -01:29:13 INF VM id=2 name=server-02 type=server -01:29:13 INF VM id=3 name=server-03 type=server -01:29:13 INF VM id=4 name=server-04 type=server -01:29:13 INF VM id=5 name=server-05 type=server -01:29:13 INF VM id=6 name=server-06 type=server -01:29:13 INF VM id=7 name=leaf-01 type=switch-vs -01:29:13 INF VM id=8 name=leaf-02 type=switch-vs -01:29:13 INF VM id=9 name=leaf-03 type=switch-vs -01:29:13 INF VM id=10 name=spine-01 type=switch-vs -01:29:13 INF VM id=11 name=spine-02 type=switch-vs -01:29:13 INF Total VM resources cpu="38 vCPUs" ram="36352 MB" disk="410 GB" -... -01:29:13 INF Preparing VM id=0 name=control-1 type=control -01:29:13 INF Copying files from=.hhfab/control-os/ignition.json to=.hhfab/vlab-vms/control-1/ignition.json -01:29:13 INF Copying files from=.hhfab/vlab-files/flatcar.img to=.hhfab/vlab-vms/control-1/os.img - 947.56 MiB / 947.56 MiB [==========================================================] 5.13 GiB/s done -01:29:14 INF Copying files from=.hhfab/vlab-files/flatcar_efi_code.fd to=.hhfab/vlab-vms/control-1/efi_code.fd -01:29:14 INF Copying files from=.hhfab/vlab-files/flatcar_efi_vars.fd to=.hhfab/vlab-vms/control-1/efi_vars.fd -01:29:14 INF Resizing VM image (may require sudo password) name=control-1 -01:29:17 INF Initializing TPM name=control-1 -... -01:29:46 INF Installing VM name=control-1 type=control -01:29:46 INF Installing VM name=server-01 type=server -01:29:46 INF Installing VM name=server-02 type=server -01:29:46 INF Installing VM name=server-03 type=server -01:29:47 INF Installing VM name=server-04 type=server -01:29:47 INF Installing VM name=server-05 type=server -01:29:47 INF Installing VM name=server-06 type=server -01:29:49 INF Running VM id=0 name=control-1 type=control -01:29:49 INF Running VM id=1 name=server-01 type=server -01:29:49 INF Running VM id=2 name=server-02 type=server -01:29:49 INF Running VM id=3 name=server-03 type=server -01:29:50 INF Running VM id=4 name=server-04 type=server -01:29:50 INF Running VM id=5 name=server-05 type=server -01:29:50 INF Running VM id=6 name=server-06 type=server -01:29:50 INF Running VM id=7 name=leaf-01 type=switch-vs -01:29:50 INF Running VM id=8 name=leaf-02 type=switch-vs -01:29:51 INF Running VM id=9 name=leaf-03 type=switch-vs -01:29:51 INF Running VM id=10 name=spine-01 type=switch-vs -01:29:51 INF Running VM id=11 name=spine-02 type=switch-vs -... -01:30:41 INF VM installed name=server-06 type=server installer=server-install -01:30:41 INF VM installed name=server-01 type=server installer=server-install -01:30:41 INF VM installed name=server-02 type=server installer=server-install -01:30:41 INF VM installed name=server-04 type=server installer=server-install -01:30:41 INF VM installed name=server-03 type=server installer=server-install -01:30:41 INF VM installed name=server-05 type=server installer=server-install -... -01:31:04 INF Running installer on VM name=control-1 type=control installer=control-install -... -01:35:15 INF Done took=3m39.586394608s -01:35:15 INF VM installed name=control-1 type=control installer=control-install -``` +11:48:22 INF Hedgehog Fabricator version=v0.30.0 +11:48:22 INF Wiring hydrated successfully mode=if-not-present +11:48:22 INF VLAB config created file=vlab/config.yaml +11:48:22 INF Downloader cache=/home/ubuntu/.hhfab-cache/v1 repo=ghcr.io prefix=githedgehog +11:48:22 INF Building installer control=control-1 +11:48:22 INF Adding recipe bin to installer control=control-1 +11:48:24 INF Adding k3s and tools to installer control=control-1 +11:48:25 INF Adding zot to installer control=control-1 +11:48:25 INF Adding cert-manager to installer control=control-1 +11:48:26 INF Adding config and included wiring to installer control=control-1 +11:48:26 INF Adding airgap artifacts to installer control=control-1 +11:48:36 INF Archiving installer path=/home/ubuntu/result/control-1-install.tgz control=control-1 +11:48:45 INF Creating ignition path=/home/ubuntu/result/control-1-install.ign control=control-1 +11:48:46 INF Taps and bridge are ready count=8 +11:48:46 INF Downloader cache=/home/ubuntu/.hhfab-cache/v1 repo=ghcr.io prefix=githedgehog +11:48:46 INF Preparing new vm=control-1 type=control +11:48:51 INF Preparing new vm=server-01 type=server +11:48:52 INF Preparing new vm=server-02 type=server +11:48:54 INF Preparing new vm=server-03 type=server +11:48:55 INF Preparing new vm=server-04 type=server +11:48:57 INF Preparing new vm=server-05 type=server +11:48:58 INF Preparing new vm=server-06 type=server +11:49:00 INF Preparing new vm=server-07 type=server +11:49:01 INF Preparing new vm=server-08 type=server +11:49:03 INF Preparing new vm=server-09 type=server +11:49:04 INF Preparing new vm=server-10 type=server +11:49:05 INF Preparing new vm=leaf-01 type=switch +11:49:06 INF Preparing new vm=leaf-02 type=switch +11:49:06 INF Preparing new vm=leaf-03 type=switch +11:49:06 INF Preparing new vm=leaf-04 type=switch +11:49:06 INF Preparing new vm=leaf-05 type=switch +11:49:06 INF Preparing new vm=spine-01 type=switch +11:49:06 INF Preparing new vm=spine-02 type=switch +11:49:06 INF Starting VMs count=18 cpu="54 vCPUs" ram="49664 MB" disk="550 GB" +11:49:59 INF Uploading control install vm=control-1 type=control +11:53:39 INF Running control install vm=control-1 type=control +11:53:40 INF control-install: 01:53:39 INF Hedgehog Fabricator Recipe version=v0.30.0 vm=control-1 +11:53:40 INF control-install: 01:53:39 INF Running control node installation vm=control-1 +12:00:32 INF control-install: 02:00:31 INF Control node installation complete vm=control-1 +12:00:32 INF Control node is ready vm=control-1 type=control +12:00:32 INF All VMs are ready -Line `VM installed name=control-1` from the installer's output means that the installer has finished. After this line +``` +When the message `INF Control node is ready vm=control-1 type=control` from the installer's output means that the installer has finished. After this line has been displayed, you can get into the control node and other VMs to watch the Fabric coming up and switches getting -provisioned. +provisioned. See [Accessing the Vlab](#accessing-the-vlab). ## Configuring VLAB VMs @@ -176,10 +127,6 @@ the host. When you enable connectivity, VMs get a default route pointing to the VPC peering you need to configure test server VMs to use the VPC attachment as a default route (or just some specific subnets). -Additionally, you can configure the size of all VMs using `hhfab vlab up --vm-size `. The flag allows you to -choose from one of the presets (compact, default, full and huge) to get the control, switch, and server VMs of different -sizes. - ## Default credentials Fabricator creates default users and keys for you to login into the control node and test servers as well as for the @@ -314,7 +261,7 @@ default 6h12m ## Reset VLAB -To reset VLAB and start over just remove the `.hhfab` directory and run `hhfab init` again. +To reset VLAB and start over directory and run `hhfab init -f` which will force overwrite your existing configuration, `fab.yaml`. ## Next steps From 98608be5cea9d8b7e62e587b255fd82a99de2006 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Wed, 23 Oct 2024 22:42:16 -0400 Subject: [PATCH 34/37] hhfab workflow, switch config --- docs/install-upgrade/build-wiring.md | 23 +++++++++++++++++++++ docs/install-upgrade/config.md | 30 ++++++++++++++++++++++------ docs/install-upgrade/overview.md | 3 +-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index d4a5f6b..220d27f 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -28,6 +28,29 @@ OPTIONS: --help, -h show help ``` +### Sample Switch Configuration +```yaml +apiVersion: wiring.githedgehog.com/v1beta1 +kind: Switch +metadata: + name: ds3000-02 +spec: + boot: + serial: ABC123XYZ + role: server-leaf + description: leaf-2 + profile: celestica-ds3000 + portBreakouts: + E1/1: 4x10G + E1/2: 4x10G + E1/17: 4x25G + E1/18: 4x25G + E1/32: 4x25G + redundancy: + group: mclag-1 + type: mclag +``` + ## Design Discussion This section is meant to help the reader understand how to assemble the primitives presented by the Fabric API into a functional fabric. diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 2a3e924..8c55be9 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -1,8 +1,27 @@ # Fabric Configuration ## Overview -The `fab.yaml` file is the configuration file for the fabric. It supplies the configuration of the users, their credentials, logging, telemetry, and other non wiring related settings. The `fab.yaml` file is composed of multiple YAML documents inside of a single file. Per the yamls spec 3 hyphens (`---`) on a single line separate the end of one document from the beginning of the next. There are two YAML documents in the `fab.yaml` file. For more information about how to use `hhfab init`, run `hhfab init --help`. +The `fab.yaml` file is the configuration file for the fabric. It supplies the configuration of the users, their credentials, logging, telemetry, and other non wiring related settings. The `fab.yaml` file is composed of multiple YAML documents inside of a single file. Per the YAML spec 3 hyphens (`---`) on a single line separate the end of one document from the beginning of the next. There are two YAML documents in the `fab.yaml` file. For more information about how to use `hhfab init`, run `hhfab init --help`. -## Fabric + +## Typical HHFAB workflows + +### HHFAB for VLAB +For a VLAB user, the typical workflow with hhfab is: +1. `hhfab init --dev` +1. `hhfab vlab gen` +1. `hhfab vlab up --kill-stale` + +The above workflow will get a user up and running with a spine-leaf VLAB. The `--kill-stale` option is supplied as its harmless on the first run and stops a lot of problems from happening with an successive run. + +### HHFAB for Physical Machines + +1. `hhfab init -c fab.yaml -w wiring-file.yaml -w extra-wiring-file.yaml` +1. `hhfab validate` +1. `hhfab build` + +After the above workflow a user will have a .img file suitable for installing the control node, then bringing up the switches which comprise the fabric. + +## Fab.yaml The fabric YAML object has 4 objects: @@ -21,8 +40,7 @@ access the configured targets. It could be done by passing `--control-proxy=true Metrics includes port speeds, counters, errors, operational status, transceivers, fans, power supplies, temperature sensors, BGP neighbors, LLDP neighbors, and more. Logs include agent logs. -Configuring the exporters and targets is currently only possible by using a YAML configuration file for the -`hhfab init -c ` command using the following format: +Configuring the exporters and targets is currently only possible by editing the `fab.yaml` configuration file. An example configuration is provided below: ```yaml spec: @@ -63,7 +81,7 @@ For additional options, see the `AlloyConfig` [struct in Fabric repo](https://gi ### Configure switch users -Configuring switch users is currently only possible by using a YAML configuration file for the `hhfab init -c ` command. You can specify users to be configured on the switches in the following format: +Configuring switch users is done either passing `--default-password-hash` to `hhfab init` or editing the resulting `fab.yaml` file emitted by `hhfab init`. You can specify users to be configured on the switches in the following format: ```yaml spec: @@ -93,7 +111,7 @@ spec: The role of the user,`operator` is read-only access to `sonic-cli` command on the switches. In order to avoid conflicts, do not use the following usernames: `operator`,`hhagent`,`netops`. ### NTP and DHCP -The control node uses public ntp servers from cloudflare and google by default. The control node runs a dhcp server on the management network. +The control node uses public ntp servers from cloudflare and google by default. The control node runs a dhcp server on the management network. See the [example file](#complete-example-file). ## Control Node The control node is the host that manages all the switches, runs k3s, and serves images. This is the YAML document configure the control node: diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index fde2f4f..f428ea8 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -36,8 +36,7 @@ The main steps to install Fabric are: 1. Boot them into ONIE Install Mode to have them automatically provisioned ## Build Control Node configuration and Installer -Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram and fabric configuration, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. - +Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram and fabric configuration, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. The first `hhfab` command to run is `hhfab init`. This will generate the main configuration file, `fab.yaml`. `fab.yaml` is responsible for almost every configuration of the fabric with the exception of the wiring. Each command and subcommand have usage messages, simply supply the `-h` flag to your command or sub command to see the available options. For example `hhfab vlab -h` and `hhfab vlab gen -h`. ### HHFAB commands to make a bootable image 1. `hhfab init --wiring wiring-lab.yaml` From 4f88837eb7e4aebcf2e3298750f4b5d2953e6637 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Thu, 24 Oct 2024 10:40:01 -0400 Subject: [PATCH 35/37] Comments from Fredi --- docs/install-upgrade/build-wiring.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index 220d27f..bde22d4 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -56,7 +56,7 @@ This section is meant to help the reader understand how to assemble the primitiv ### VPC -A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC belong to the same broadcast domain and can communicate with each other. The hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to exist beyond a single switch, which gives flexibility when the physical world meets the digital. +A VPC allows for isolation at layer 3. This is the main building block for users when creating their architecture. Hosts inside of a VPC belong to the same broadcast domain and can communicate with each other, if desired a single VPC can be configured with multiple broadcast domains. The hosts inside of a VPC will likely need to connect to other VPCs or the outside world. To communicate between two VPC a *peering* will need to be created. A VPC can be a logical separation of workloads. By separating these workloads additional controls are available. The logical separation doesn't have to be the traditional database, web, and compute layers it could be development teams who need isolation, it could be tenants inside of an office building, or any separation that allows for better control of the network. Once your VPCs are decided, the rest of the fabric will come together. With the VPCs decided traffic can be prioritized, security can be put into place, and the wiring can begin. The fabric allows for the VPC to span more than a than one switch, which provides great flexibility, for instance workload mobility. ### Connection @@ -82,7 +82,7 @@ VPCs need VPC Peerings to talk to each other. VPC Peerings come in two varieties #### Local VPC Peering -When there is no dedicated border/peering switch available in the fabric we can use local VPC peering. This kind of peering tries to send traffic between the two VPC's on the switch where either of the VPC's has workloads attached. Due to limitation in the Sonic network operating system this kind of peering bandwidth is limited to the number of VPC loopbacks you have selected while initializing the fabric. +When there is no dedicated border/peering switch available in the fabric we can use local VPC peering. This kind of peering tries sends traffic between the two VPC's on the switch where either of the VPC's has workloads attached. Due to limitation in the Sonic network operating system this kind of peering bandwidth is limited to the number of VPC loopbacks you have selected while initializing the fabric. Traffic between the VPCs will use the loopback interface, the bandwidth of this connection will be equal to the bandwidth of port used in the loopback. #### Remote VPC Peering @@ -91,5 +91,5 @@ Remote Peering is used when you need a high bandwidth connection between the VPC #### VPC Loopback -A VPC loopback is a physical cable with both ends plugged into the same switch, suggested but not required to be the adjacent ports. This loopback allows two different VPCs to communicate with each other. +A VPC loopback is a physical cable with both ends plugged into the same switch, suggested but not required to be the adjacent ports. This loopback allows two different VPCs to communicate with each other. This is due to a Broadcom limitation. From 96c1315da22568b3bd07d7a7daab912eba478e83 Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Thu, 24 Oct 2024 12:27:57 -0400 Subject: [PATCH 36/37] incremental commit --- docs/install-upgrade/config.md | 2 + docs/install-upgrade/overview.md | 1 + docs/vlab/demo.md | 121 ++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/docs/install-upgrade/config.md b/docs/install-upgrade/config.md index 8c55be9..a8c4da2 100644 --- a/docs/install-upgrade/config.md +++ b/docs/install-upgrade/config.md @@ -6,7 +6,9 @@ The `fab.yaml` file is the configuration file for the fabric. It supplies the co ## Typical HHFAB workflows ### HHFAB for VLAB + For a VLAB user, the typical workflow with hhfab is: + 1. `hhfab init --dev` 1. `hhfab vlab gen` 1. `hhfab vlab up --kill-stale` diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index f428ea8..a2fdd66 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -39,6 +39,7 @@ The main steps to install Fabric are: Hedgehog has created a command line utility, called `hhfab`, that helps generate the wiring diagram and fabric configuration, validate the supplied configurations, and generate an installation image (.img) suitable for writing to a USB flash drive or mounting via IPMI virtual media. The first `hhfab` command to run is `hhfab init`. This will generate the main configuration file, `fab.yaml`. `fab.yaml` is responsible for almost every configuration of the fabric with the exception of the wiring. Each command and subcommand have usage messages, simply supply the `-h` flag to your command or sub command to see the available options. For example `hhfab vlab -h` and `hhfab vlab gen -h`. ### HHFAB commands to make a bootable image + 1. `hhfab init --wiring wiring-lab.yaml` 1. The `init` command generates a `fab.yaml` file, edit the `fab.yaml` file for your needs 1. ensure the correct boot disk (e.g. `/dev/sda`) and control node NIC names are supplied diff --git a/docs/vlab/demo.md b/docs/vlab/demo.md index 64d727c..3c65102 100644 --- a/docs/vlab/demo.md +++ b/docs/vlab/demo.md @@ -86,7 +86,8 @@ graph TD L1 & L2 & L2 & L3 & L4 & L5 <----> S1 & S2 ``` -## Creating and attaching VPCs +## Manual VPC creation +### Creating and attaching VPCs You can create and attach VPCs to the VMs using the `kubectl fabric vpc` command on the Control Node or outside of the cluster using the kubeconfig. For example, run the following commands to create 2 VPCs with a single subnet each, a DHCP @@ -138,7 +139,7 @@ spine-02 spine VS-05 18m 4 4 v0.23.0 In this example, the values in columns `APPLIEDG` and `CURRENTG` are equal which means that the requested configuration has been applied. -## Setting up networking on test servers +### Setting up networking on test servers You can use `hhfab vlab ssh` on the host to SSH into the test servers and configure networking there. For example, for both `server-01` (MCLAG attached to both `leaf-01` and `leaf-02`) we need to configure a bond with a VLAN on top of it @@ -194,7 +195,7 @@ core@server-02 ~ $ ip a valid_lft forever preferred_lft forever ``` -## Testing connectivity before peering +### Testing connectivity before peering You can test connectivity between the servers before peering the switches using the `ping` command: @@ -220,7 +221,7 @@ From 10.0.2.1 icmp_seq=3 Destination Net Unreachable 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2004ms ``` -## Peering VPCs and testing connectivity +### Peering VPCs and testing connectivity To enable connectivity between the VPCs, peer them using `kubectl fabric vpc peer`: @@ -293,6 +294,118 @@ From 10.0.1.1 icmp_seq=3 Destination Net Unreachable 3 packets transmitted, 3 received, +3 duplicates, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 6.987/8.720/9.595/1.226 ms ``` +## Utility based VPC creation + +### Setup VPCs +`hhfab vlab` includes a utility to create VPCs in vlab. This utility is a `hhfab vlab` sub-command. `hhfab vlab setup-vpcs`. + +```console +NAME: + hhfab vlab setup-vpcs - setup VPCs and VPCAttachments for all servers and configure networking on them + +USAGE: + hhfab vlab setup-vpcs [command options] + +OPTIONS: + --dns-servers value, --dns value [ --dns-servers value, --dns value ] DNS servers for VPCs advertised by DHCP + --force-clenup, -f start with removing all existing VPCs and VPCAttachments (default: false) + --help, -h show help + --interface-mtu value, --mtu value interface MTU for VPCs advertised by DHCP (default: 0) + --ipns value IPv4 namespace for VPCs (default: "default") + --name value, -n value name of the VM or HW to access + --servers-per-subnet value, --servers value number of servers per subnet (default: 1) + --subnets-per-vpc value, --subnets value number of subnets per VPC (default: 1) + --time-servers value, --ntp value [ --time-servers value, --ntp value ] Time servers for VPCs advertised by DHCP + --vlanns value VLAN namespace for VPCs (default: "default") + --wait-switches-ready, --wait wait for switches to be ready before and after configuring VPCs and VPCAttachments (default: true) + + Global options: + + --brief, -b brief output (only warn and error) (default: false) [$HHFAB_BRIEF] + --cache-dir DIR use cache dir DIR for caching downloaded files (default: "/home/ubuntu/.hhfab-cache") [$HHFAB_CACHE_DIR] + --verbose, -v verbose output (includes debug) (default: false) [$HHFAB_VERBOSE] + --workdir PATH run as if hhfab was started in PATH instead of the current working directory (default: "/home/ubuntu") [$HHFAB_WORK_DIR] +``` + +### Setup Peering +`hhfab vlab` includes a utility to create VPC peerings in VLAB. This utility is a `hhfab vlab` sub-command. `hhfab vlab setup-peerings`. + +```console +NAME: + hhfab vlab setup-peerings - setup VPC and External Peerings per requests (remove all if empty) + +USAGE: + Setup test scenario with VPC/External Peerings by specifying requests in the format described below. + + Example command: + + $ hhfab vlab setup-peerings 1+2 2+4:r=border 1~as5835 2~as5835:subnets=sub1,sub2:prefixes=0.0.0.0/0,22.22.22.0/24 + + Which will produce: + 1. VPC peering between vpc-01 and vpc-02 + 2. Remote VPC peering between vpc-02 and vpc-04 on switch group named border + 3. External peering for vpc-01 with External as5835 with default vpc subnet and any routes from external permitted + 4. External peering for vpc-02 with External as5835 with subnets sub1 and sub2 exposed from vpc-02 and default route + from external permitted as well any route that belongs to 22.22.22.0/24 + + VPC Peerings: + + 1+2 -- VPC peering between vpc-01 and vpc-02 + demo-1+demo-2 -- VPC peering between demo-1 and demo-2 + 1+2:r -- remote VPC peering between vpc-01 and vpc-02 on switch group if only one switch group is present + 1+2:r=border -- remote VPC peering between vpc-01 and vpc-02 on switch group named border + 1+2:remote=border -- same as above + + External Peerings: + + 1~as5835 -- external peering for vpc-01 with External as5835 + 1~ -- external peering for vpc-1 with external if only one external is present for ipv4 namespace of vpc-01, allowing + default subnet and any route from external + 1~:subnets=default@prefixes=0.0.0.0/0 -- external peering for vpc-1 with auth external with default vpc subnet and + default route from external permitted + 1~as5835:subnets=default,other:prefixes=0.0.0.0/0_le32_ge32,22.22.22.0/24 -- same but with more details + 1~as5835:s=default,other:p=0.0.0.0/0_le32_ge32,22.22.22.0/24 -- same as above + +OPTIONS: + --help, -h show help + --name value, -n value name of the VM or HW to access + --wait-switches-ready, --wait wait for switches to be ready before before and after configuring peerings (default: true) + + Global options: + + --brief, -b brief output (only warn and error) (default: false) [$HHFAB_BRIEF] + --cache-dir DIR use cache dir DIR for caching downloaded files (default: "/home/ubuntu/.hhfab-cache") [$HHFAB_CACHE_DIR] + --verbose, -v verbose output (includes debug) (default: false) [$HHFAB_VERBOSE] + --workdir PATH run as if hhfab was started in PATH instead of the current working directory (default: "/home/ubuntu") [$HHFAB_WORK_DIR] +``` + +### Test Connectivity +`hhfab vlab` includes a utility to test connectivity between servers inside VLAB. This utility is a `hhfab vlab` sub-command. `hhfab vlab test-connectivity`. + +```console +NAME: + hhfab vlab test-connectivity - test connectivity between all servers + +USAGE: + hhfab vlab test-connectivity [command options] + +OPTIONS: + --curls value number of curl tests to run for each server to test external connectivity (0 to disable) (default: 3) + --help, -h show help + --iperfs value seconds of iperf3 test to run between each pair of reachable servers (0 to disable) (default: 10) + --iperfs-speed value minimum speed in Mbits/s for iperf3 test to consider successful (0 to not check speeds) (default: 7000) + --name value, -n value name of the VM or HW to access + --pings value number of pings to send between each pair of servers (0 to disable) (default: 5) + --wait-switches-ready, --wait wait for switches to be ready before testing connectivity (default: true) + + Global options: + + --brief, -b brief output (only warn and error) (default: false) [$HHFAB_BRIEF] + --cache-dir DIR use cache dir DIR for caching downloaded files (default: "/home/ubuntu/.hhfab-cache") [$HHFAB_CACHE_DIR] + --verbose, -v verbose output (includes debug) (default: false) [$HHFAB_VERBOSE] + --workdir PATH run as if hhfab was started in PATH instead of the current working directory (default: "/home/ubuntu") [$HHFAB_WORK_DIR] + +``` ## Using VPCs with overlapping subnets From ccefb54d7fcfd9be38c3048e2fbd2a324967ea6d Mon Sep 17 00:00:00 2001 From: Logan Blyth Date: Thu, 24 Oct 2024 13:50:43 -0400 Subject: [PATCH 37/37] last changes --- docs/install-upgrade/build-wiring.md | 2 +- docs/install-upgrade/overview.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install-upgrade/build-wiring.md b/docs/install-upgrade/build-wiring.md index bde22d4..f0cb925 100644 --- a/docs/install-upgrade/build-wiring.md +++ b/docs/install-upgrade/build-wiring.md @@ -5,7 +5,7 @@ ## Overview -A wiring diagram is a YAML file that is a digital representation of your network. You can find more YAML level details in the User Guide section [switch features and port naming](../user-guide/profiles.md) and the [api](../reference/api.md). It's mandatory to for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. +A wiring diagram is a YAML file that is a digital representation of your network. You can find more YAML level details in the User Guide section [switch features and port naming](../user-guide/profiles.md) and the [api](../reference/api.md). It's mandatory for all switches to reference a `SwitchProfile` in the `spec.profile` of the `Switch` object. Only port naming defined by switch profiles could be used in the wiring diagram, NOS (or any other) port names aren't supported. In the meantime, to have a look at working wiring diagram for Hedgehog Fabric, run the sample generator that produces VLAB-compatible wiring diagrams: diff --git a/docs/install-upgrade/overview.md b/docs/install-upgrade/overview.md index a2fdd66..da4926a 100644 --- a/docs/install-upgrade/overview.md +++ b/docs/install-upgrade/overview.md @@ -9,8 +9,8 @@ * An 8 GB USB flash drive, if you are not using virtual media * Have a machine to function as the Fabric Control Node. [System Requirements](./requirements.md) as well as IPMI access to it to install the OS. -* Have a management switch with at least 1 10GbE port -* Have enough [Supported Switches](./supported-devices.md) for your Fabric +* A management switch with at least 1 10GbE port +* Enough [Supported Switches](./supported-devices.md) for your Fabric ## Overview of Install Process