Internal Docker registry host that is visible only inside teh cluster.

cdi-func-test-registry-host - a host that runs docker registry and is accessible from inside the cluster via
cdi-func-test-registry-host.kube-system host name. The registry is populated with images taken from /tmp/shared/images. It is used by functional tests.
Example of usage:
1. inspect
With skopeo acces registry to ispect image  built from /tmp/shared/images/tinyCore.iso
skopeo inspect --tls-verify=false docker://cdi-func-test-registry-host.kube-system/tinycore.iso

2. Copy
skopeo copy --src-tls-verify=false docker://cdi-func-test-registry-host.kube-system/tinycore.iso dir:/tmp/download

Technical details:
Registry is run in a dedicated  service cdi-func-test-registry-host.
In the same pod there are 3 containers:
1. cdi-func-test-registry - runs registry:2 with self signed certificate that listens on port 443
2. cdi-func-test-registry-init - used to pouplate /tmp/shared/images volume with images created from /test/images/tinuCore.iso and with certificate generated during container image build
3. cdi-func-test-registry-populate - encapsulted all images of /tmp/shared/images in docker images and pushes them to the registry
This commit is contained in:
annastopel 2018-12-30 14:18:25 +02:00
parent 91889b935d
commit 0a18aa3d09
14 changed files with 532 additions and 7 deletions

View File

@ -12,8 +12,8 @@
#See the License for the specific language governing permissions and
#limitations under the License.
.PHONY: build build-controller build-importer build-cloner build-apiserver build-uploadproxy build-uploadserver build-functest-image-init build-functest-image-http build-functest \
docker docker-controller docker-cloner docker-importer docker-apiserver docker-uploadproxy docker-uploadserver docker-functest-image-init docker-functest-image-http\
.PHONY: build build-controller build-importer build-cloner build-apiserver build-uploadproxy build-uploadserver build-functest-image-init build-functest-image-http build-functest-registry-init build-func-test-registry-populate build-functest \
docker docker-controller docker-cloner docker-importer docker-apiserver docker-uploadproxy docker-uploadserver docker-functest-image-init docker-functest-image-http docker-functest-registry-populate docker-functest-registry docker-functest-registry-init \
cluster-sync cluster-sync-controller cluster-sync-cloner cluster-sync-importer cluster-sync-apiserver cluster-sync-uploadproxy cluster-sync-uploadserver \
test test-functional test-unit test-lint \
publish \
@ -45,7 +45,7 @@ apidocs:
${DO} "./hack/update-codegen.sh && ./hack/gen-swagger-doc/gen-swagger-docs.sh v1alpha1 html"
build:
${DO} "./hack/build/build-go.sh clean && ./hack/build/build-go.sh build ${WHAT} && ./hack/build/build-cdi-func-test-file-host.sh && DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} ./hack/build/build-manifests.sh ${WHAT} && ./hack/build/build-copy-artifacts.sh ${WHAT}"
${DO} "./hack/build/build-go.sh clean && ./hack/build/build-go.sh build ${WHAT} && ./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-cdi-func-test-registry-host.sh && DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} ./hack/build/build-manifests.sh ${WHAT} && ./hack/build/build-copy-artifacts.sh ${WHAT}"
build-controller: WHAT = cmd/cdi-controller
build-controller: build
@ -97,12 +97,20 @@ docker-uploadproxy: docker
docker-uploadserver: WHAT = cmd/cdi-uploadserver
docker-uploadserver: docker
docker-functest-image: docker-functest-image-http docker-functest-image-init
docker-functest-image: docker-functest-image-http docker-functest-image-init docker-functest-registry-init docker-functest-registry-populate docker-functest-registry
docker-functest-image-init: WHAT = tools/cdi-func-test-file-host-init
docker-functest-image-init: docker
docker-functest-image-http: WHAT = tools/cdi-func-test-file-host-http
docker-functest-image-http: # no code to compile, just build image
./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-docker.sh build ${WHAT}
docker-functest-registry-init: WHAT = tools/cdi-func-test-registry-init
docker-functest-registry-init: docker
docker-functest-registry-populate: WHAT = tools/cdi-func-test-registry-populate
docker-functest-registry-populate: # no code to compile, just build image
./hack/build/build-cdi-func-test-registry-host.sh && ./hack/build/build-docker.sh build ${WHAT}
docker-functest-registry: WHAT = tools/cdi-func-test-registry
docker-functest-registry: # no code to compile, just build image
./hack/build/build-cdi-func-test-registry-host.sh && ./hack/build/build-docker.sh build ${WHAT}
push: docker
./hack/build/build-docker.sh push ${WHAT}
@ -168,4 +176,5 @@ functest:
functest-image-host: WHAT=tools/cdi-func-test-file-host-init
functest-image-host: manifests build
${DO} ./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-docker.sh "tools/cdi-func-test-file-host-init tools/cdi-func-test-file-host-http"
${DO} ./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-docker.sh "tools/cdi-func-test-file-host-init tools/cdi-func-test-file-host-http tools/cdi-func-test-registry-init tools/cdi-func-test-registry tools/cdi-func-test-registry-populate"

View File

@ -41,3 +41,4 @@ fi
./cluster/kubectl.sh apply -f ./manifests/generated/cdi-controller.yaml
# Start functional test HTTP server.
./cluster/kubectl.sh apply -f ./manifests/generated/file-host.yaml
./cluster/kubectl.sh apply -f ./manifests/generated/registry-host.yaml

View File

@ -46,6 +46,10 @@ elif [[ $image == $OPENSHIFT_IMAGE ]]; then
./cluster/.kubectl config set-cluster node01:8443 --insecure-skip-tls-verify=true
fi
# Temporary until image is updated with provisioner that sets this field
# This field is required by buildah tool
$gocli ssh node01 -- sudo sysctl -w user.max_user_namespaces=1024
echo 'Wait until all nodes are ready'
until [[ $(./cluster/kubectl.sh get nodes --no-headers | wc -l) -eq $(./cluster/kubectl.sh get nodes --no-headers | grep " Ready" | wc -l) ]]; do
sleep 1

View File

@ -53,6 +53,9 @@ The standard workflow is performed inside a helper container to normalize the bu
- `docker-functest-image`: Compile and build the file host image for functional tests
- `docker-functest-image-init`: Compile and build the file host init image for functional tests
- `docker-functest-image-http`: Only build the file host http container for functional tests
- `docker-functest-registry-init`:Compile and build the registry init image for functional testa
- `docker-functest-registry-populate`: Only build registry-populate container for functional tests
- `docker-functest-registry`: Only build docker-registry container for functional tests
- Note: there is no target for the S3 container, an offical Minio container is used instead
- `manifests`: Generate a cdi-controller manifest in `manifests/generated/`. Accepts [make variables](#make-variables) DOCKER_TAG, DOCKER_REPO, VERBOSITY, and PULL_POLICY
- `push`: compiles, builds, and pushes to the repo passed in `DOCKER_REPO=<my repo>`

View File

@ -0,0 +1,39 @@
#!/usr/bin/env bash
#Copyright 2018 The CDI Authors.
#
#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.
set -euo pipefail
script_dir="$(readlink -f $(dirname $0))"
source "${script_dir}"/common.sh
source "${script_dir}"/config.sh
REGISTRY_INIT_PATH="tools/${FUNC_TEST_REGISTRY_INIT}"
${BUILD_DIR}/build-copy-artifacts.sh "${REGISTRY_INIT_PATH}"
OUT_PATH="${OUT_DIR}/tools"
mkdir -p "${OUT_PATH}/${FUNC_TEST_REGISTRY}"
mkdir -p "${OUT_PATH}/${FUNC_TEST_REGISTRY_POPULATE}"
mkdir -p "${OUT_PATH}/${FUNC_TEST_REGISTRY_INIT}"
DOCKER_REPO=""
cp ${BUILD_DIR}/docker/${FUNC_TEST_REGISTRY}/* ${OUT_PATH}/${FUNC_TEST_REGISTRY}/
cp ${BUILD_DIR}/docker/${FUNC_TEST_REGISTRY_POPULATE}/* ${OUT_PATH}/${FUNC_TEST_REGISTRY_POPULATE}/
cp -r ${BUILD_DIR}/docker/${FUNC_TEST_REGISTRY_INIT}/* ${OUT_PATH}/${FUNC_TEST_REGISTRY_INIT}/
cp "${CDI_DIR}/tests/images/tinyCore.iso" ${OUT_PATH}/${FUNC_TEST_REGISTRY_INIT}/

View File

@ -20,8 +20,11 @@ UPLOADPROXY="cdi-uploadproxy"
UPLOADSERVER="cdi-uploadserver"
FUNC_TEST_INIT="cdi-func-test-file-host-init"
FUNC_TEST_HTTP="cdi-func-test-file-host-http"
FUNC_TEST_REGISTRY="cdi-func-test-registry"
FUNC_TEST_REGISTRY_POPULATE="cdi-func-test-registry-populate"
FUNC_TEST_REGISTRY_INIT="cdi-func-test-registry-init"
BINARIES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} tools/${FUNC_TEST_INIT}"
BINARIES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_REGISTRY_INIT}"
CDI_PKGS="cmd/ pkg/ test/"
CONTROLLER_MAIN="cmd/${CONTROLLER}"
@ -31,7 +34,7 @@ APISERVER_MAIN="cmd/${APISERVER}"
UPLOADPROXY_MAIN="cmd/${UPLOADPROXY}"
UPLOADSERVER_MAIN="cmd/${UPLOADSERVER}"
DOCKER_IMAGES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_HTTP}"
DOCKER_IMAGES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_HTTP} tools/${FUNC_TEST_REGISTRY} tools/${FUNC_TEST_REGISTRY_POPULATE} tools/${FUNC_TEST_REGISTRY_INIT}"
DOCKER_REPO=${DOCKER_REPO:-kubevirt}
CONTROLLER_IMAGE_NAME=${CONTROLLER_IMAGE_NAME:-cdi-controller}
IMPORTER_IMAGE_NAME=${IMPORTER_IMAGE_NAME:-cdi-importer}

View File

@ -0,0 +1,23 @@
FROM fedora:28
RUN mkdir -p /tmp/shared /tmp/source
RUN dnf install -y qemu-img qemu-block-curl && dnf clean all
COPY cdi-func-test-registry-init /usr/bin/
RUN chmod u+x /usr/bin/cdi-func-test-registry-init
COPY tinyCore.iso /tmp/source/tinyCore.iso
RUN mkdir -p /tmp/source/certs
RUN dnf install -y openssl
RUN openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout /tmp/source/certs/domain.key \
-x509 -days 365 \
-subj "/C=GB/ST=TLV/L=TLV/O=RedHat/OU=CDI/CN=cdi-docker-registry-host.kube-system" \
-out /tmp/source/certs/domain.crt
ENTRYPOINT ["cdi-func-test-registry-init", "-alsologtostderr"]

View File

@ -0,0 +1,9 @@
FROM fedora:28
RUN mkdir -p /tmp/shared /tmp/source
RUN dnf install -y buildah
ADD populate-registry.sh /
RUN chmod u+x /populate-registry.sh
ENTRYPOINT ["./populate-registry.sh"]

View File

@ -0,0 +1,107 @@
#!/bin/sh
# Populate regisry host with disk images encapsulated inside container images.
# Disk images are taken from /tmp/shared/images directory populated by cdi-func-test-registry-init
# Container images are built with buildah
#images args
IMAGES_SRC=$1 #path to files to be encapsulated in docker image
IMAGES_CTR=$2 #path to directories with Dockerfile per file
#registry args
REGISTRY_HOST=$3 #host name of docker registry
REGISTRY_PORT=$4 #port of docker registry
REGISTRY_TLS="--tls-verify=false"
#health args
HEALTH_PATH=$5 #path f or health indicators - shared between popuplate and registry-host containers
HEALTH_PERIOD=$6
READYNESS_PATH=$7 #path f or readyness indicators - shared between popuplate and registry-host containers
READYNESS_PERIOD=$8
function ready {
echo "readiness"
touch $1
}
function health {
echo "health"
touch $1
}
#Convert all images to docker build consumable format
DIR="-dir"
DOCKERFILE="Dockerfile"
function prepareImages {
images_in=$1
images_out=$2
rm -rf $images_out
mkdir -p $images_out
cp $images_in* $images_out
cd $images_out
for FILENAME in $(ls); do
mkdir -p $FILENAME$DIR
cp $FILENAME $FILENAME$DIR
FILE=$FILENAME$DIR"/"$DOCKERFILE
/bin/cat >$FILE <<-EOF
FROM scratch
ADD / $FILENAME
EOF
rm $FILENAME
done
}
function error {
if [ "$1" -ne "0" ]; then
echo "Exiting on error"
exit -1
fi
}
#Iterate over all images build them and push them into cdi registry
function pushImages {
images=$1
registry_host=$2
registry_port=$3
registry_tls=$4
registry=$registry_host":"$registry_port
retval=$?
shopt -s nullglob
for IMAGEDIR in *$DIR; do
cd $IMAGEDIR
FILE=$(ls | grep -v $DOCKERFILE)
declare -l FILE
FILE=$FILE
echo "building image "$FILE
buildah bud -t $FILE":buildah" $images"/"$IMAGEDIR"/"; $retval
error $retval
echo "pushing image "$FILE" to registry-service: "$resgistry
buildah push $registry_tls $FILE":buildah" "docker://"$registry"/"$FILE; $retVal
error $retval
cd ../
done
}
#start health beat
health $HEALTH_PATH $HEALTH_PERIOD &
#prepare and poush images
prepareImages $IMAGES_SRC $IMAGES_CTR
pushImages $IMAGES_CTR $REGISTRY_HOST $REGISTRY_PORT $REGISTRY_TLS
#mark container as ready
ready $READYNESS_PATH $READYNESS_PERIOD &
#sleep forever
trap : TERM INT
sleep infinity & wait

View File

@ -0,0 +1,10 @@
FROM registry:2
ADD registry-config.yml /etc/docker/registry/
ADD start-registry.sh /
RUN chmod u+x /start-registry.sh
EXPOSE 443
ENTRYPOINT ["/start-registry.sh"]

View File

@ -0,0 +1,21 @@
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :443
tls:
certificate: /tmp/shared/certs/domain.crt
key: /tmp/shared/certs/domain.key
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3

View File

@ -0,0 +1,2 @@
#!/bin/sh
registry serve /etc/docker/registry/registry-config.yml

View File

@ -0,0 +1,112 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
creationTimestamp: null
labels:
cdi.kubevirt.io/registry.vol.pvc: registry-vol-pvc
name: registry-vol-pvc
namespace: {{ .Namespace }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
status: {}
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: cdi-docker-registry-host
namespace: {{ .Namespace }}
labels:
cdi.kubevirt.io: ""
cdi.kubevirt.io/testing.registry: ""
spec:
selector:
matchLabels:
cdi.kubevirt.io/testing.registry: ""
replicas: 1
template:
metadata:
labels:
cdi.kubevirt.io/testing.registry: ""
spec:
initContainers:
- name: registry-init
image: {{ .DockerRepo }}/cdi-func-test-registry-init:{{ .DockerTag }}
imagePullPolicy: {{ .PullPolicy }}
args: ["-inCertDir", "/tmp/source/certs", "-outCertDir", "/tmp/shared/certs", "-inFile", "/tmp/source/tinyCore.iso", "-outDir", "/tmp/shared/images"]
volumeMounts:
- name: "images"
mountPath: "/tmp/shared"
containers:
- name: registry
image: {{ .DockerRepo }}/cdi-func-test-registry:{{ .DockerTag }}
imagePullPolicy: {{ .PullPolicy }}
ports:
- name: sec-docker-reg
containerPort: 443
resources: {}
volumeMounts:
- name: "registry-volume"
mountPath: "/var/run/docker.sock"
- name: "health"
mountPath: "/tmp/health"
- name: "images"
mountPath: "/tmp/shared"
readinessProbe:
exec:
command:
- cat
- /tmp/health/ready
initialDelaySeconds: 20
periodSeconds: 20
- name: registry-populate
image: {{ .DockerRepo }}/cdi-func-test-registry-populate:{{ .DockerTag }}
imagePullPolicy: {{ .PullPolicy }}
args: [ "/tmp/shared/images/", "/tmp/docker-images", "127.0.0.1", "443", "/tmp/health/healthy", "15", "/tmp/health/ready", "15"]
volumeMounts:
- name: "images"
mountPath: "/tmp/shared"
- name: "health"
mountPath: "/tmp/health"
readinessProbe:
exec:
command:
- cat
- /tmp/health/ready
initialDelaySeconds: 20
periodSeconds: 20
livenessProbe:
exec:
command:
- cat
- /tmp/health/healthy
initialDelaySeconds: 20
periodSeconds: 20
volumes:
- name: "images"
emptyDir: {}
- name: "health"
emptyDir: {}
- name: "registry-volume"
persistentVolumeClaim:
claimName: registry-vol-pvc
---
apiVersion: v1
kind: Service
metadata:
name: cdi-docker-registry-host
namespace: {{ .Namespace }}
labels:
cdi.kubevirt.io: ""
cdi.kubevirt.io/testing.registry: ""
spec:
selector:
cdi.kubevirt.io/testing.registry: ""
ports:
- name: sec-docker-reg
port: 443
targetPort: 443

View File

@ -0,0 +1,182 @@
//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.
package main
import (
"flag"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
"kubevirt.io/containerized-data-importer/tests/utils"
)
func main() {
inCertDir := flag.String("inCertDir", "", "")
outCertDir := flag.String("outCertDir", "", "")
inFile := flag.String("inFile", "", "")
outDir := flag.String("outDir", "", "")
flag.Parse()
ft := &formatTable{
[]string{""},
[]string{".tar"},
[]string{".gz"},
[]string{".xz"},
[]string{".tar", ".gz"},
[]string{".tar", ".xz"},
[]string{".qcow2"},
}
if err := ft.generateFiles(*inFile, *outDir); err != nil {
glog.Fatal(errors.Wrapf(err, "generating files from %s to %s' errored: ", *inFile, *outDir))
}
if err := ft.copyCertDir(*inCertDir, *outCertDir); err != nil {
glog.Fatal(errors.Wrapf(err, "copy certificate directory %s' errored: ", outCertDir))
}
}
func (ft formatTable) generateFiles(inFile, outDir string) error {
glog.Info("Generating test files")
if err := os.MkdirAll(outDir, 0777); err != nil {
return err
}
if err := ft.initializeTestFiles(inFile, outDir); err != nil {
return err
}
glog.Info("File initialization completed without error")
return nil
}
func (ft formatTable) copyFile(src, dest string, info os.FileInfo) error {
if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
return err
}
f, err := os.Create(dest)
if err != nil {
return err
}
defer f.Close()
if err = os.Chmod(f.Name(), info.Mode()); err != nil {
return err
}
s, err := os.Open(src)
if err != nil {
return err
}
defer s.Close()
_, err = io.Copy(f, s)
return err
}
func (ft formatTable) copyCertDir(inCertDir string, outCertDir string) error {
glog.Info("Copying certificates")
if err := os.MkdirAll(outCertDir, 0777); err != nil {
glog.Fatal(errors.Wrapf(err, "'mkdir %s' errored: ", outCertDir))
}
contents, err := ioutil.ReadDir(inCertDir)
if err != nil {
return err
}
for _, content := range contents {
cs, cd := filepath.Join(inCertDir, content.Name()), filepath.Join(outCertDir, content.Name())
if err := ft.copyFile(cs, cd, content); err != nil {
// If any error exit
return err
}
}
glog.Info("Copying certificates completed without errors")
return nil
}
type formatTable [][]string
func (ft formatTable) initializeTestFiles(inFile, outDir string) error {
sem := make(chan bool, 3)
errChan := make(chan error, len(ft))
reportError := func(err error, msg string, format ...interface{}) {
e := errors.Wrapf(err, msg, format...)
glog.Error(e)
errChan <- e
return
}
for _, fList := range ft {
sem <- true
go func(i, o string, f []string) {
defer func() { <-sem }()
glog.Infof("Generating file %s\n", f)
ext := strings.Join(f, "")
tmpDir := filepath.Join(o, "tmp"+ext)
if err := os.Mkdir(tmpDir, 0777); err != nil {
reportError(err, "Error creating temp dir %s", tmpDir)
return
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
reportError(err, "Error deleting tmp dir %s", tmpDir)
}
}()
glog.Infof("Mkdir %s\n", tmpDir)
p, err := utils.FormatTestData(i, tmpDir, f...)
if err != nil {
reportError(err, "Error formatting files")
return
}
if err = os.Rename(p, filepath.Join(o, filepath.Base(p))); err != nil {
reportError(err, "Error moving file %s to %s", p, o)
return
}
glog.Infof("Generated file %q\n", p)
}(inFile, outDir, fList)
}
for i := 0; i < cap(sem); i++ {
sem <- true
}
close(errChan)
if len(errChan) > 0 {
for err := range errChan {
glog.Error(err)
}
return errors.New("Error(s) occurred during file conversion")
}
return nil
}