Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 Support for full netplan spec #797

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
145 changes: 145 additions & 0 deletions hack/quicktype/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# 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):
$(CRI_BIN) build \
--build-arg "BASE_IMAGE_BUILD=$(BASE_IMAGE_BUILD)" \
--build-arg "BASE_IMAGE_WORK=$(BASE_IMAGE_WORK)" \
-t $(QUICKTYPE_IMAGE) \
-f $(abspath $(QUICK_DIR)/Dockerfile) \
$(abspath $(QUICK_DIR))
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.
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