Skip to content

Commit

Permalink
Build calico windows upgrade image (#1278)
Browse files Browse the repository at this point in the history
* Add building of calico windows upgrade image
  • Loading branch information
lmm committed Oct 29, 2021
1 parent 4c6cba9 commit f111f7f
Show file tree
Hide file tree
Showing 4 changed files with 276 additions and 11 deletions.
14 changes: 12 additions & 2 deletions .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,16 @@ blocks:
dependencies: []
task:
jobs:
- name: "Build All Images"
- name: "Build all node images"
execution_time_limit:
minutes: 120
commands:
- TEST_IMAGE_BUILD=true make image-all
- name: "Build Windows images"
execution_time_limit:
minutes: 120
commands:
- make build-windows-upgrade-archive image-tar-windows-all

- name: "General Tests"
dependencies: []
Expand Down Expand Up @@ -130,7 +135,11 @@ blocks:
- echo $DOCKER_TOKEN | docker login --username "$DOCKER_USER" --password-stdin
- echo $QUAY_TOKEN | docker login --username "$QUAY_USER" --password-stdin quay.io
- export BRANCH_NAME=$SEMAPHORE_GIT_BRANCH
- if [ -z "${SEMAPHORE_GIT_PR_NUMBER}" ]; then make image-all cd CONFIRM=true; fi
- >-
if [ -z "${SEMAPHORE_GIT_PR_NUMBER}" ]; then
make image-all cd CONFIRM=true
make build-windows-upgrade-archive image-tar-windows-all cd-windows-upgrade CONFIRM=true
fi
- name: "build windows archive"
dependencies: ["General Tests", "System Tests", "Specialized Tests"]
Expand All @@ -142,6 +151,7 @@ blocks:
commands:
- export BRANCH_NAME=$SEMAPHORE_GIT_BRANCH
- make release-windows-archive VERSION=${BRANCH_NAME}
- make build-windows-upgrade-archive

promotions:
# Run the pin update process in case there were a backlog of pin update requests
Expand Down
180 changes: 171 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ DEV_TAG_SUFFIX ?=0.dev

# If this is a release, also tag and push additional images.
ifeq ($(RELEASE),true)
NODE_IMAGE ?=node
DEV_REGISTRIES ?=quay.io/calico calico $(RELEASE_REGISTRIES)
NODE_IMAGE ?=node
WINDOWS_UPGRADE_IMAGE ?=windows-upgrade
DEV_REGISTRIES ?=quay.io/calico calico $(RELEASE_REGISTRIES)
else
NODE_IMAGE ?=calico/node
DEV_REGISTRIES ?=quay.io docker.io
NODE_IMAGE ?=calico/node
WINDOWS_UPGRADE_IMAGE ?=calico/windows-upgrade
DEV_REGISTRIES ?=quay.io docker.io
endif

WINDOWS_VERSIONS?=1809 2004 20H2 ltsc2022
BUILD_IMAGES ?=$(NODE_IMAGE)
LIBBPF_DOCKER_PATH=/go/src/github.com/projectcalico/node/bin/third-party/libbpf/src
BPF_GPL_DOCKER_PATH=/go/src/github.com/projectcalico/node/bin/bpf/bpf-gpl
Expand Down Expand Up @@ -142,6 +145,22 @@ WINDOWS_ARCHIVE_FILES := \
MICROSOFT_SDN_VERSION := 0d7593e5c8d4c2347079a7a6dbd9eb034ae19a44
MICROSOFT_SDN_GITHUB_RAW_URL := https://raw.githubusercontent.com/microsoft/SDN/$(MICROSOFT_SDN_VERSION)

WINDOWS_UPGRADE_ROOT ?= windows-upgrade
WINDOWS_UPGRADE_DIST = dist/windows-upgrade

# The directory that holds temporary files used to build the windows upgrade zip
# archive.
WINDOWS_UPGRADE_DIST_STAGE = $(WINDOWS_UPGRADE_DIST)/stage
WINDOWS_UPGRADE_INSTALL_FILE ?= $(WINDOWS_UPGRADE_DIST_STAGE)/install-calico-windows.ps1
WINDOWS_UPGRADE_INSTALL_ZIP ?= $(WINDOWS_UPGRADE_DIST_STAGE)/calico-windows-$(WINDOWS_ARCHIVE_TAG).zip
WINDOWS_UPGRADE_SCRIPT ?= $(WINDOWS_UPGRADE_DIST_STAGE)/calico-upgrade.ps1

# The directory used for the upgrade image docker build context.
WINDOWS_UPGRADE_BUILD ?= $(WINDOWS_UPGRADE_ROOT)/build

# The final zip archive used in the upgrade image.
WINDOWS_UPGRADE_ARCHIVE ?= $(WINDOWS_UPGRADE_BUILD)/calico-windows-upgrade.zip

# Variables used by the tests
LOCAL_IP_ENV?=$(shell ip route get 8.8.8.8 | head -1 | awk '{print $$7}')
ST_TO_RUN?=tests/st/
Expand All @@ -167,7 +186,7 @@ SRC_FILES=$(shell find ./pkg -name '*.go')
BINDIR?=bin

## Clean enough that a new release build will be clean
clean:
clean: clean-windows-upgrade
find . -name '*.created' -exec rm -f {} +
find . -name '*.pyc' -exec rm -f {} +
rm -rf .go-pkg-cache
Expand All @@ -176,6 +195,8 @@ clean:
rm -f $(WINDOWS_ARCHIVE_ROOT)/libs/hns/hns.psm1
rm -f $(WINDOWS_ARCHIVE_ROOT)/libs/hns/License.txt
rm -f $(WINDOWS_ARCHIVE_ROOT)/cni/*.exe
rm -f $(WINDOWS_UPGRADE_INSTALL_FILE)
rm -f $(WINDOWS_UPGRADE_BUILD)/*.zip
rm -rf filesystem/included-source
rm -rf dist
rm -rf filesystem/etc/calico/confd/conf.d filesystem/etc/calico/confd/config filesystem/etc/calico/confd/templates
Expand All @@ -186,6 +207,11 @@ clean:
# Delete images that we built in this repo
docker rmi $(NODE_IMAGE):latest-$(ARCH) || true
docker rmi $(TEST_CONTAINER_NAME) || true
docker rmi $(addprefix $(WINDOWS_UPGRADE_IMAGE):latest-,$(WINDOWS_VERSIONS)) || true

clean-windows-upgrade:
-rm -f "$(WINDOWS_UPGRADE_DIST_STAGE)"
-rm -rf "$(WINDOWS_UPGRADE_BUILD)"

###############################################################################
# Updating pins
Expand Down Expand Up @@ -564,7 +590,7 @@ st: image remote-deps dist/calicoctl busybox.tar calico-node.tar workload.tar ru
ci: mod-download static-checks fv image-all build-windows-archive st

## Deploys images to registry
cd: cd-common
cd: cd-common cd-windows-upgrade


check-boring-ssl: $(NODE_CONTAINER_BIN_DIR)/calico-node-amd64
Expand Down Expand Up @@ -606,11 +632,16 @@ ifneq ($(VERSION), $(GIT_VERSION))
endif
$(MAKE) image-all RELEASE=true
$(MAKE) retag-build-images-with-registries RELEASE=true IMAGETAG=$(VERSION)
# Generate the `latest` images.
# Generate the `latest` node images.
$(MAKE) retag-build-images-with-registries RELEASE=true IMAGETAG=latest
# Generate the Windows zip archives.
$(MAKE) release-windows-archive
$(MAKE) release-windows-upgrade-archive
# Generate the Windows upgrade image tarballs (this must come after the
# upgrade archive)
$(MAKE) image-tar-windows-all

## Produces the Windows ZIP archive for the release.
## Produces the Windows installation ZIP archive for the release.
release-windows-archive $(WINDOWS_ARCHIVE): release-prereqs
$(MAKE) build-windows-archive WINDOWS_ARCHIVE_TAG=$(VERSION)

Expand All @@ -634,9 +665,12 @@ endif
# Push the git tag.
git push origin $(VERSION)

# Push images.
# Push node images.
$(MAKE) push-images-to-registries push-manifests IMAGETAG=$(VERSION) RELEASE=true CONFIRM=true

# Push Windows upgrade images.
$(MAKE) cd-windows-upgrade RELEASE=true CONFIRM=true

# Push Windows artifacts to GitHub release.
# Requires ghr: https://github.com/tcnksm/ghr
# Requires GITHUB_TOKEN environment variable set.
Expand Down Expand Up @@ -730,6 +764,134 @@ build-windows-archive: $(WINDOWS_ARCHIVE_FILES) windows-packaging/nssm-$(WINDOWS
$(WINDOWS_ARCHIVE_BINARY): $(WINDOWS_BINARY)
cp $< $@

# Ensure the upgrade image docker build folder exists.
$(WINDOWS_UPGRADE_BUILD):
-mkdir -p $(WINDOWS_UPGRADE_BUILD)

# Ensure the directory for temporary files used to build the windows upgrade zip
# archive exists.
$(WINDOWS_UPGRADE_DIST_STAGE):
-mkdir -p $(WINDOWS_UPGRADE_DIST_STAGE)

# Copy the upgrade script to the temporary directory where we build the windows
# upgrade zip file.
$(WINDOWS_UPGRADE_SCRIPT): $(WINDOWS_UPGRADE_DIST_STAGE)
cp $(WINDOWS_UPGRADE_ROOT)/calico-upgrade.ps1 $@

# Copy the install zip archive to the temporary directory where we build the windows
# upgrade zip file.
$(WINDOWS_UPGRADE_INSTALL_ZIP): build-windows-archive $(WINDOWS_UPGRADE_DIST_STAGE)
cp $(WINDOWS_ARCHIVE) $@

# Get the install script into the temporary directory where we build the windows
# upgrade zip file. The version of the install script depends on whether there
# is a released version for the branch; otherwise the master version of the
# script is used.
$(WINDOWS_UPGRADE_INSTALL_FILE): $(WINDOWS_UPGRADE_DIST_STAGE)
# Truncated git version in the vX.Y version string our docs site uses.
$(eval ver := $(shell echo $(WINDOWS_ARCHIVE_TAG) | sed -ne 's/\(v[0-9]\+\.[0-9]\+\).*/\1/p' ))
# The vX.Y.Z version string.
$(eval fullver := $(shell echo $(WINDOWS_ARCHIVE_TAG) | sed -ne 's/\(v[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' ))
@echo vX.Y version is $(ver)
@echo vX.Y.Z version is $(fullver)
@if git show-ref --tags $(fullver) ; then \
echo "Tag $(fullver) exists, using released version of installation script" ; \
curl --fail https://docs.projectcalico.org/archive/$(ver)/scripts/install-calico-windows.ps1 -o $(WINDOWS_UPGRADE_INSTALL_FILE) ; \
else \
echo "Tag $(fullver) doesn't exist yet, using master version of installation script" ; \
curl --fail https://docs.projectcalico.org/master/scripts/install-calico-windows.ps1 -o $(WINDOWS_UPGRADE_INSTALL_FILE) ; \
fi

# Produces the Windows upgrade ZIP archive for the release.
release-windows-upgrade-archive: release-prereqs
$(MAKE) build-windows-upgrade-archive WINDOWS_ARCHIVE_TAG=$(VERSION)

# Build the Windows upgrade zip archive.
build-windows-upgrade-archive: clean-windows-upgrade $(WINDOWS_UPGRADE_INSTALL_ZIP) $(WINDOWS_UPGRADE_INSTALL_FILE) $(WINDOWS_UPGRADE_SCRIPT) $(WINDOWS_UPGRADE_BUILD)
rm $(WINDOWS_UPGRADE_ARCHIVE) || true
cd $(WINDOWS_UPGRADE_DIST_STAGE) && zip -r "$(CURDIR)/$(WINDOWS_UPGRADE_ARCHIVE)" *.zip *.ps1

# Sets up the docker builder used to create Windows image tarballs.
setup-windows-builder:
-docker buildx rm calico-windows-upgrade-builder
docker buildx create --name=calico-windows-upgrade-builder --use --platform windows/amd64

# Builds all the Windows image tarballs for each version in WINDOWS_VERSIONS
image-tar-windows-all: setup-windows-builder $(addprefix sub-image-tar-windows-,$(WINDOWS_VERSIONS))

CRANE_BINDMOUNT_CMD := \
docker run --rm \
--net=host \
--init \
--entrypoint /bin/sh \
-e LOCAL_USER_ID=$(LOCAL_USER_ID) \
-v $(CURDIR):/go/src/$(PACKAGE_NAME):rw \
-v $(DOCKER_CONFIG):/root/.docker/config.json \
-w /go/src/$(PACKAGE_NAME) \
$(CALICO_BUILD) -c $(double_quote)crane

DOCKER_MANIFEST_CMD := docker manifest

ifdef CONFIRM
CRANE_BINDMOUNT = $(CRANE_BINDMOUNT_CMD)
DOCKER_MANIFEST = $(DOCKER_MANIFEST_CMD)
else
CRANE_BINDMOUNT = echo [DRY RUN] $(CRANE_BINDMOUNT_CMD)
DOCKER_MANIFEST = echo [DRY RUN] $(DOCKER_MANIFEST_CMD)
endif

# Uses the docker builder to create a Windows image tarball for a single Windows
# version.
sub-image-tar-windows-%:
-mkdir -p $(WINDOWS_UPGRADE_DIST)
cd $(WINDOWS_UPGRADE_ROOT) && \
docker buildx build \
--platform windows/amd64 \
--output=type=docker,dest=$(CURDIR)/$(WINDOWS_UPGRADE_DIST)/image-$(GIT_VERSION)-$*.tar \
--pull \
--no-cache \
--build-arg=WINDOWS_VERSION=$* .

# The calico-windows-upgrade cd is different because we do not build docker images directly.
# Since the build machine is linux, we output the images to a tarball. (We can
# produce images but there will be no output because docker images
# built for Windows cannot be loaded on linux.)
#
# The resulting image tarball is then pushed to registries during cd/release.
# The image tarballs are located in dist/windows-upgrade and have files names
# with the format 'image-v3.21.0-2-abcdef-20H2.tar'.
#
# In addition to pushing the individual images, we also create the manifest
# directly using 'docker manifest'. This is possible because Semaphore is using
# a recent enough docker CLI version (20.10.0)
#
# - Create the manifest with 'docker manifest create' using the list of all images.
# - For each windows version, 'docker manifest annotate' its image with "os.image: <windows_version>".
# <windows_version> is the version string that looks like, e.g. 10.0.19041.1288.
# Setting os.image in the manifest is required for Windows hosts to load the
# correct image in manifest.
# - Finally we push the manifest, "purging" the local manifest.
cd-windows-upgrade:
for registry in $(DEV_REGISTRIES); do \
echo Pushing Windows images to $${registry}; \
all_images=""; \
manifest_image="$${registry}/$(WINDOWS_UPGRADE_IMAGE):$(GIT_VERSION)"; \
for win_ver in $(WINDOWS_VERSIONS); do \
image_tar="$(WINDOWS_UPGRADE_DIST)/image-$(GIT_VERSION)-$${win_ver}.tar"; \
image="$${registry}/$(WINDOWS_UPGRADE_IMAGE):$(GIT_VERSION)-windows-$${win_ver}"; \
echo Pushing image $${image} ...; \
$(CRANE_BINDMOUNT) push $${image_tar} $${image}$(double_quote) & \
all_images="$${all_images} $${image}"; \
done; \
wait; \
$(DOCKER_MANIFEST) create --amend $${manifest_image} $${all_images}; \
for win_ver in $(WINDOWS_VERSIONS); do \
version=$$(docker manifest inspect mcr.microsoft.com/windows/nanoserver:$${win_ver} | grep "os.version" | head -n 1 | awk -F\" '{print $$4}'); \
image="$${registry}/$(WINDOWS_UPGRADE_IMAGE):$(GIT_VERSION)-windows-$${win_ver}"; \
$(DOCKER_MANIFEST) annotate --os windows --arch amd64 --os-version $${version} $${manifest_image} $${image}; \
done; \
$(DOCKER_MANIFEST) push --purge $${manifest_image}; \
done ;

###############################################################################
# Utilities
Expand Down
42 changes: 42 additions & 0 deletions windows-upgrade/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) 2021 Tigera, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
ARG WINDOWS_VERSION
FROM --platform=linux/amd64 alpine:latest as base

# We can't RUN commands in the Windows image build.
# Create dirs we need that we copy over in the final stage.
RUN mkdir /CalicoUpgrade /CalicoBin

ADD build/* /CalicoBin/

FROM mcr.microsoft.com/windows/nanoserver:${WINDOWS_VERSION}

COPY --from=base /CalicoUpgrade /CalicoUpgrade
COPY --from=base /CalicoBin /CalicoBin

# nanoserver defaults to ContainerUser however we need admin to run icacls
USER ContainerAdministrator

ENTRYPOINT cmd.exe \
/C \
copy /y c:\\CalicoBin\\calico-windows-upgrade.zip c:\\CalicoUpgrade & \
tar -x -f c:\\CalicoUpgrade\calico-windows-upgrade.zip -C c:\\CalicoUpgrade & \
del c:\\CalicoUpgrade\calico-windows-upgrade.zip & \
icacls.exe c:\\CalicoUpgrade & \
icacls.exe c:\\CalicoUpgrade /inheritance:r & \
icacls.exe c:\\CalicoUpgrade /grant:r SYSTEM:(OI)(CI)(F) & \
icacls.exe c:\\CalicoUpgrade /grant:r BUILTIN\Administrators:(OI)(CI)(F) & \
icacls.exe c:\\CalicoUpgrade /grant:r BUILTIN\Users:(OI)(CI)(RX) & \
icacls.exe c:\\CalicoUpgrade & \
ping -t localhost > NUL
51 changes: 51 additions & 0 deletions windows-upgrade/calico-upgrade.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) 2021 Tigera, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

$rootDir = "c:\CalicoWindows"
$installZipFile = "c:\calico-windows.zip"

$date = Get-Date -UFormat "%Y-%m-%d"
$logFile = "c:\calico-upgrade.$date.log"

function Log {
param ([String]$value)
$stamp = Get-Date -UFormat "%Y-%m-%d %R:%S"
Add-content -Path $logFile -Value "$stamp [INFO] $value"
}

Log "Starting calico upgrade"
$zipFile = $Get-ChildItem -path . -filter calico-windows-upgrade*.zip | Select -expandproperty Name
Expand-Archive -Path $zipFile -DestinationPath $PSScriptRoot
Remove-Item -Path $zipFile

Log "Files in c:\CalicoUpgrade:"
$files = ls c:\CalicoUpgrade | Out-String
Log $files

Log "Copying installation zip file"
cp $PSScriptRoot\*.zip $installZipFile

Log "Starting installation script..."
& $PSScriptRoot\install-calico-windows.ps1 *>> $logFile

Log "Cleaning up"
Remove-Item -Path $PSScriptRoot\*.ps1
Remove-Item -Path $PSScriptRoot\*.zip
$oldCalicoNode = "$rootDir\calico-node.exe.to-be-replaced"
if (Test-Path $oldCalicoNode)
{
Remove-Item -Path $oldCalicoNode
}

Log "Finished upgrade"

0 comments on commit f111f7f

Please sign in to comment.