Skip to content

Commit

Permalink
Support for full netplan spec
Browse files Browse the repository at this point in the history
This patch adds support for the complete netplan specification.
  • Loading branch information
akutz committed Nov 13, 2024
1 parent 5654a42 commit 0be4a9a
Show file tree
Hide file tree
Showing 27 changed files with 6,299 additions and 243 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: 'pkg/util/cloudinit/schema/package-lock.json'
cache-dependency-path: 'hack/quicktype/package-lock.json'
- name: Install Go
uses: actions/setup-go@v5
with:
Expand Down
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ issues:
exclude-dirs:
- external
- pkg/util/cloudinit/schema
- pkg/util/netplan/schema
exclude-files:
- ".*generated.*\\.go"
exclude:
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ generate-go: ## Generate golang sources
paths=github.com/vmware-tanzu/vm-operator/external/capabilities/... \
object:headerFile=./hack/boilerplate/boilerplate.generatego.txt
$(MAKE) -C ./pkg/util/cloudinit/schema $@
$(MAKE) -C ./pkg/util/netplan/schema $@

.PHONY: generate-manifests
generate-manifests: $(CONTROLLER_GEN)
Expand Down
2 changes: 2 additions & 0 deletions hack/quicktype/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
.receipt-*
14 changes: 14 additions & 0 deletions hack/quicktype/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2024 VMware, Inc. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

ARG BASE_IMAGE_BUILD=node:22
ARG BASE_IMAGE_WORK=gcr.io/distroless/nodejs22-debian12

FROM ${BASE_IMAGE_BUILD} AS build
WORKDIR /quicktype
COPY package.json package-lock.json* ./
RUN npm ci --prefix /quicktype quicktype

FROM ${BASE_IMAGE_WORK}
COPY --from=build /quicktype /quicktype
WORKDIR /output
146 changes: 146 additions & 0 deletions hack/quicktype/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Copyright (c) 2024 VMware, Inc. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Required vars
SCHEMA_IN ?=
OUTPUT_GO ?=
TOOLS_DIR ?=
QUICK_DIR ?=
START_TYP ?=

# If you update this file, please follow
# https://suva.sh/posts/well-documented-makefiles

# Ensure Make is run with bash shell as some syntax below is bash-specific
SHELL := /usr/bin/env bash

.DEFAULT_GOAL := help

# Get the information about the platform on which the tools are built/run.
GOHOSTOS := $(shell go env GOHOSTOS)
GOHOSTARCH := $(shell go env GOHOSTARCH)
GOHOSTOSARCH := $(GOHOSTOS)_$(GOHOSTARCH)

# Directories.
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin/$(GOHOSTOSARCH)
export PATH := $(abspath $(TOOLS_BIN_DIR)):$(PATH)

# Binaries.
QUICKTYPE := $(QUICK_DIR)/node_modules/.bin/quicktype
GOIMPORTS := $(TOOLS_BIN_DIR)/goimports

# Images.
BASE_IMAGE_BUILD ?= node:22
BASE_IMAGE_WORK ?= gcr.io/distroless/nodejs22-debian12
QUICKTYPE_IMAGE_NAME := vmop-quicktype
QUICKTYPE_IMAGE_VERSION := latest
QUICKTYPE_IMAGE ?= $(QUICKTYPE_IMAGE_NAME):$(QUICKTYPE_IMAGE_VERSION)
QUICKTYPE_IMAGE_RECEIPT := $(abspath $(QUICK_DIR)/.receipt-$(QUICKTYPE_IMAGE_NAME)-$(shell echo '$(BASE_IMAGE_BUILD)-$(BASE_IMAGE_WORK)' | md5sum | awk '{print $$1}'))

# CRI_BIN is the path to the container runtime binary.
ifeq (,$(strip $(GITHUB_RUN_ID)))
# Prefer podman locally.
CRI_BIN := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)
else
# Prefer docker in GitHub actions.
CRI_BIN := $(shell command -v docker 2>/dev/null || command -v podman 2>/dev/null)
endif
export CRI_BIN

# Select how to run quicktype.
QUICKTYPE_METHOD ?= local
ifeq (local,$(QUICKTYPE_METHOD))
ifeq (,$(shell command -v npm))
QUICKTYPE_METHOD ?= container
endif
endif

# Tooling binaries
GOIMPORTS := $(TOOLS_BIN_DIR)/goimports


## --------------------------------------
## Help
## --------------------------------------

help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)


## --------------------------------------
## Tooling Binaries
## --------------------------------------

TOOLING_BINARIES := $(GOIMPORTS)
tools: $(TOOLING_BINARIES) ## Build tooling binaries
$(TOOLING_BINARIES):
make -C $(TOOLS_DIR) $(@F)


## --------------------------------------
## Image
## --------------------------------------

$(QUICKTYPE_IMAGE_RECEIPT):
cd $(QUICK_DIR) && \
$(CRI_BIN) build \
--build-arg "BASE_IMAGE_BUILD=$(BASE_IMAGE_BUILD)" \
--build-arg "BASE_IMAGE_WORK=$(BASE_IMAGE_WORK)" \
-t $(QUICKTYPE_IMAGE) \
-f Dockerfile \
. && \
touch $(QUICKTYPE_IMAGE_RECEIPT)
image-build-quicktype: $(QUICKTYPE_IMAGE_RECEIPT)


## --------------------------------------
## Binaries
## --------------------------------------

quicktype: $(QUICKTYPE)
$(QUICKTYPE): $(QUICK_DIR)/package.json
cd $(QUICK_DIR) && npm ci --user quicktype


## --------------------------------------
## Generate
## --------------------------------------

generate-schema: $(SCHEMA_IN)
generate-schema: ## Generate the schema

$(OUTPUT_GO): $(SCHEMA_IN) | $(GOIMPORTS)
ifeq (local,$(QUICKTYPE_METHOD))
$(OUTPUT_GO): | $(QUICKTYPE)
$(QUICKTYPE) \
--src $(SCHEMA_IN) --src-lang schema \
--out $@ --lang go --package schema \
--top-level $(START_TYP)
$(GOIMPORTS) -w $@
else
$(OUTPUT_GO): | $(QUICKTYPE_IMAGE_RECEIPT)
$(CRI_BIN) run -it --rm \
-v $$(pwd):/output \
-v $(abspath $(SCHEMA_IN)):/schema.json \
$(QUICKTYPE_IMAGE) \
/quicktype/node_modules/quicktype/dist/index.js \
--src /schema.json \
--src-lang schema \
--out /output/schema.go \
--lang go \
--package schema \
--top-level $(START_TYP)
mv -f schema.go $@
$(GOIMPORTS) -w $@
endif

generate-go: $(OUTPUT_GO)
generate-go: ## Generate the go source code from the schema

## --------------------------------------
## Cleanup
## --------------------------------------

.PHONY: clean
clean: ## Run all the clean targets
rm -f $(SCHEMA_IN) $(OUTPUT_GO) $(QUICKTYPE_IMAGE_RECEIPT)
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion pkg/providers/vsphere/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const (

// NetPlanVersion points to the version used for Network config.
// For more information, please see https://cloudinit.readthedocs.io/en/latest/topics/network-config-format-v2.html
NetPlanVersion = 2
NetPlanVersion = int64(2)

PCIPassthruMMIOOverrideAnnotation = pkg.VMOperatorKey + "/pci-passthru-64bit-mmio-size"
PCIPassthruMMIOExtraConfigKey = "pciPassthru.use64bitMMIO" //nolint:gosec
Expand Down
102 changes: 45 additions & 57 deletions pkg/providers/vsphere/network/netplan.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,87 +7,75 @@ import (
"strings"

"github.com/vmware-tanzu/vm-operator/pkg/providers/vsphere/constants"
"github.com/vmware-tanzu/vm-operator/pkg/util/netplan"
"github.com/vmware-tanzu/vm-operator/pkg/util/ptr"
)

// Netplan representation described in https://via.vmw.com/cloud-init-netplan // FIXME: 404.
type Netplan struct {
Version int `json:"version,omitempty"`
Ethernets map[string]NetplanEthernet `json:"ethernets,omitempty"`
}

type NetplanEthernet struct {
Match NetplanEthernetMatch `json:"match,omitempty"`
SetName string `json:"set-name,omitempty"`
Dhcp4 bool `json:"dhcp4,omitempty"`
Dhcp6 bool `json:"dhcp6,omitempty"`
Addresses []string `json:"addresses,omitempty"`
Gateway4 string `json:"gateway4,omitempty"`
Gateway6 string `json:"gateway6,omitempty"`
MTU int64 `json:"mtu,omitempty"`
Nameservers NetplanEthernetNameserver `json:"nameservers,omitempty"`
Routes []NetplanEthernetRoute `json:"routes,omitempty"`
}

type NetplanEthernetMatch struct {
MacAddress string `json:"macaddress,omitempty"`
}

type NetplanEthernetNameserver struct {
Addresses []string `json:"addresses,omitempty"`
Search []string `json:"search,omitempty"`
}

type NetplanEthernetRoute struct {
To string `json:"to"`
Via string `json:"via"`
Metric int32 `json:"metric,omitempty"`
}

func NetPlanCustomization(result NetworkInterfaceResults) (*Netplan, error) {
netPlan := &Netplan{
func NetPlanCustomization(result NetworkInterfaceResults) (*netplan.Network, error) {
netPlan := &netplan.Network{
Version: constants.NetPlanVersion,
Ethernets: make(map[string]NetplanEthernet),
Ethernets: make(map[string]netplan.Ethernet),
}

for _, r := range result.Results {
npEth := NetplanEthernet{
Match: NetplanEthernetMatch{
MacAddress: NormalizeNetplanMac(r.MacAddress),
npEth := netplan.Ethernet{
Match: &netplan.Match{
Macaddress: ptr.To(NormalizeNetplanMac(r.MacAddress)),
},
SetName: r.GuestDeviceName,
MTU: r.MTU,
Nameservers: NetplanEthernetNameserver{
SetName: &r.GuestDeviceName,
MTU: &r.MTU,
Nameservers: &netplan.Nameserver{
Addresses: r.Nameservers,
Search: r.SearchDomains,
},
}

npEth.Dhcp4 = r.DHCP4
npEth.Dhcp6 = r.DHCP6
npEth.Dhcp4 = &r.DHCP4
npEth.Dhcp6 = &r.DHCP6

if !npEth.Dhcp4 {
for _, ipConfig := range r.IPConfigs {
if !*npEth.Dhcp4 {
for i := range r.IPConfigs {
ipConfig := r.IPConfigs[i]
if ipConfig.IsIPv4 {
if npEth.Gateway4 == "" {
npEth.Gateway4 = ipConfig.Gateway
if npEth.Gateway4 == nil || *npEth.Gateway4 == "" {
npEth.Gateway4 = &ipConfig.Gateway
}
npEth.Addresses = append(npEth.Addresses, ipConfig.IPCIDR)
npEth.Addresses = append(
npEth.Addresses,
netplan.Address{
String: &ipConfig.IPCIDR,
},
)
}
}
}
if !npEth.Dhcp6 {
for _, ipConfig := range r.IPConfigs {
if !*npEth.Dhcp6 {
for i := range r.IPConfigs {
ipConfig := r.IPConfigs[i]
if !ipConfig.IsIPv4 {
if npEth.Gateway6 == "" {
npEth.Gateway6 = ipConfig.Gateway
if npEth.Gateway6 == nil || *npEth.Gateway6 == "" {
npEth.Gateway6 = &ipConfig.Gateway
}
npEth.Addresses = append(npEth.Addresses, ipConfig.IPCIDR)
npEth.Addresses = append(
npEth.Addresses,
netplan.Address{
String: &ipConfig.IPCIDR,
},
)
}
}
}

for _, route := range r.Routes {
npEth.Routes = append(npEth.Routes, NetplanEthernetRoute(route))
for i := range r.Routes {
route := r.Routes[i]
npEth.Routes = append(
npEth.Routes,
netplan.Route{
To: &route.To,
Metric: ptr.To(int64(route.Metric)),
Via: &route.Via,
},
)
}

netPlan.Ethernets[r.Name] = npEth
Expand Down
Loading

0 comments on commit 0be4a9a

Please sign in to comment.