Skip to content

Commit

Permalink
allow kpack to build windows pods
Browse files Browse the repository at this point in the history
- wait for dns on windows. This is dues to the fact that windows
containers on docker don't start up without their network ready so we
have to wait. we think that this can be removed when containerd is the default runtime. In the build-init binary
we don't error on timeout because we assume that it timed out due to an
incorrect host, so we want the normal error for that to still apply.
- create network wait launcher binary. This is used to execute the
lifecycle containers during the build after the network is ready in
windows containers. it is built with build-init and copied to a shared
volume during the prepare step. we also think this can be removed when
containerd is the default runtime
- Copy git repository to workspace directory becase clone directly to workspace was causing issues on Windows
- add os to builder status
- Update openapi spec with latest openapi gen binary
- add windows images to controller yaml
- caching is not currently implemented for windows builds because the
DefaultStorageClass isn't always compatible with windows. This will
require more investigation

Co-authored-by: Tom Kennedy <ktom@vmware.com>
Co-authored-by: Anthony Emengo <aemengo@vmware.com>
Co-authored-by: Matthew McNew <mmcnew@pivotal.io>
  • Loading branch information
3 people committed Jan 11, 2021
1 parent 55e1007 commit 2729e9a
Show file tree
Hide file tree
Showing 16 changed files with 788 additions and 77 deletions.
3 changes: 3 additions & 0 deletions api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -4604,6 +4604,9 @@
"$ref": "#/definitions/kpack.build.v1alpha1.OrderEntry"
}
},
"os": {
"type": "string"
},
"stack": {
"default": {},
"$ref": "#/definitions/kpack.build.v1alpha1.BuildStack"
Expand Down
89 changes: 82 additions & 7 deletions cmd/build-init/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package main

import (
"flag"
"io"
"log"
"net"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/pkg/errors"
Expand All @@ -29,6 +33,7 @@ var (
gitRevision = flag.String("git-revision", os.Getenv("GIT_REVISION"), "The Git revision to make the repository HEAD.")
blobURL = flag.String("blob-url", os.Getenv("BLOB_URL"), "The url of the source code blob.")
registryImage = flag.String("registry-image", os.Getenv("REGISTRY_IMAGE"), "The registry location of the source code image.")
hostName = flag.String("dns-probe-hostname", os.Getenv("DNS_PROBE_HOSTNAME"), "hostname to dns poll")

buildChanges = flag.String("build-changes", os.Getenv("BUILD_CHANGES"), "JSON string of build changes and their reason")

Expand All @@ -48,20 +53,27 @@ func init() {
}

const (
secretsHome = "/builder/home"
appDir = "/workspace"
platformDir = "/platform"
buildSecretsDir = "/var/build-secrets"
imagePullSecretsDir = "/imagePullSecrets"
builderPullSecretsDir = "/builderPullSecrets"
projectMetadataDir = "/projectMetadata"
secretsHome = "/builder/home"
appDir = "/workspace"
platformDir = "/platform"
buildSecretsDir = "/var/build-secrets"
imagePullSecretsDir = "/imagePullSecrets"
builderPullSecretsDir = "/builderPullSecrets"
projectMetadataDir = "/projectMetadata"
networkWaitLauncherDir = "/networkWait"
networkWaitLauncherBinary = "network-wait-launcher.exe"
)

func main() {
flag.Parse()

logger := log.New(os.Stdout, "", 0)

err := prepareForWindows(*hostName)
if err != nil {
logger.Fatal(err)
}

if err := buildchange.Log(logger, *buildChanges); err != nil {
logger.Println(err)
}
Expand Down Expand Up @@ -126,6 +138,26 @@ func main() {
}
}

func prepareForWindows(hostname string) error {
if runtime.GOOS != "windows" {
return nil
}

executablePath, err := os.Executable()
if err != nil {
return err
}

err = copyFile(filepath.Join(filepath.Dir(executablePath), networkWaitLauncherBinary), filepath.Join(networkWaitLauncherDir, networkWaitLauncherBinary))
if err != nil {
return err
}

waitForDns(hostname)

return nil
}

func fetchSource(logger *log.Logger, serviceAccountCreds dockercreds.DockerCreds) error {
switch {
case *gitURL != "":
Expand Down Expand Up @@ -175,3 +207,46 @@ func logLoadingSecrets(logger *log.Logger, secretsSlices ...[]string) {
}
}
}

func waitForDns(hostname string) {
timeoutChan := time.After(10 * time.Second)
tickerChan := time.NewTicker(time.Second)
defer tickerChan.Stop()

for {
select {
case <-timeoutChan:
return
case <-tickerChan.C:
if _, err := net.LookupIP(hostname); err == nil {
return
}
}
}
}

func copyFile(src, dest string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()

destFile, err := os.Create(dest)
if err != nil {
return err
}
defer destFile.Close()

if _, err = io.Copy(destFile, srcFile); err != nil {
return err
}

srcInfo, err := os.Stat(src)
if err != nil {
return err
}

return os.Chmod(dest, srcInfo.Mode())
}

18 changes: 11 additions & 7 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ var (
kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
masterURL = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")

buildInitImage = flag.String("build-init-image", os.Getenv("BUILD_INIT_IMAGE"), "The image used to initialize a build")
rebaseImage = flag.String("rebase-image", os.Getenv("REBASE_IMAGE"), "The image used to perform rebases")
completionImage = flag.String("completion-image", os.Getenv("COMPLETION_IMAGE"), "The image used to finish a build")
lifecycleImage = flag.String("lifecycle-image", os.Getenv("LIFECYCLE_IMAGE"), "The image used to provide lifecycle binaries")
buildInitImage = flag.String("build-init-image", os.Getenv("BUILD_INIT_IMAGE"), "The image used to initialize a build")
buildInitWindowsImage = flag.String("build-init-windows-image", os.Getenv("BUILD_INIT_WINDOWS_IMAGE"), "The image used to initialize a build on windows")
rebaseImage = flag.String("rebase-image", os.Getenv("REBASE_IMAGE"), "The image used to perform rebases")
completionImage = flag.String("completion-image", os.Getenv("COMPLETION_IMAGE"), "The image used to finish a build")
completionWindowsImage = flag.String("completion-windows-image", os.Getenv("COMPLETION_WINDOWS_IMAGE"), "The image used to finish a build on windows")
lifecycleImage = flag.String("lifecycle-image", os.Getenv("LIFECYCLE_IMAGE"), "The image used to provide lifecycle binaries")
)

func main() {
Expand Down Expand Up @@ -123,9 +125,11 @@ func main() {

buildpodGenerator := &buildpod.Generator{
BuildPodConfig: v1alpha1.BuildPodImages{
BuildInitImage: *buildInitImage,
CompletionImage: *completionImage,
RebaseImage: *rebaseImage,
BuildInitImage: *buildInitImage,
CompletionImage: *completionImage,
RebaseImage: *rebaseImage,
BuildInitWindowsImage: *buildInitWindowsImage,
CompletionWindowsImage: *completionWindowsImage,
},
K8sClient: k8sClient,
KeychainFactory: keychainFactory,
Expand Down
49 changes: 49 additions & 0 deletions cmd/network-wait-launcher/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"errors"
"log"
"net"
"os"
"os/exec"
"time"
)

func main() {
// example: /kpack/network-wait-launcher gcr.io -- completion --notary-url="some-url"

hostname := os.Args[1]
command := os.Args[3:]

if err := waitForDns(hostname); err != nil {
log.Fatal(err)
}

cmd := exec.Command(command[0], command[1:]...)

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}

}

func waitForDns(hostname string) error {
timeoutChan := time.After(10 * time.Second)
tickerChan := time.NewTicker(time.Second)
defer tickerChan.Stop()

for {
select {
case <-timeoutChan:
return errors.New("timeout waiting for network")
case <-tickerChan.C:
_, err := net.LookupIP(hostname)
if err == nil {
return nil
}
}
}

}
26 changes: 26 additions & 0 deletions config/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ data:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: build-init-windows-image
namespace: kpack
data:
image: #@ data.values.build_init_windows_image
---
apiVersion: v1
kind: ConfigMap
metadata:
name: rebase-image
namespace: kpack
Expand All @@ -33,6 +41,14 @@ metadata:
data:
image: #@ data.values.completion_image
---
apiVersion: v1
kind: ConfigMap
metadata:
name: completion-windows-image
namespace: kpack
data:
image: #@ data.values.completion_windows_image
---
apiVersion: apps/v1
kind: Deployment
metadata:
Expand Down Expand Up @@ -71,6 +87,11 @@ spec:
configMapKeyRef:
name: build-init-image
key: image
- name: BUILD_INIT_WINDOWS_IMAGE
valueFrom:
configMapKeyRef:
name: build-init-windows-image
key: image
- name: REBASE_IMAGE
valueFrom:
configMapKeyRef:
Expand All @@ -81,6 +102,11 @@ spec:
configMapKeyRef:
name: completion-image
key: image
- name: COMPLETION_WINDOWS_IMAGE
valueFrom:
configMapKeyRef:
name: completion-windows-image
key: image
- name: LIFECYCLE_IMAGE
valueFrom:
configMapKeyRef:
Expand Down
2 changes: 2 additions & 0 deletions config/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
controller_image: gcr.io/controller
webhook_image: gcr.io/webhook
build_init_image: gcr.io/build-init
build_init_windows_image: gcr.io/cf-build-service-public/kpack/build-init-windows
rebase_image: gcr.io/rebase
completion_image: gcr.io/completion
completion_windows_image: gcr.io/cf-build-service-public/kpack/completion-windows
lifecycle_image: gcr.io/lifecycle
version: dev
Loading

0 comments on commit 2729e9a

Please sign in to comment.