Skip to content

Commit

Permalink
Merge pull request redhat-developer#2 from rhd-gitops-example/wtam-ka…
Browse files Browse the repository at this point in the history
…niko

Rename  flag "credentials" to "dockerconfigjson" and more
  • Loading branch information
jaideepr97 authored Jul 28, 2020
2 parents 8f12adf + 25acb47 commit f36ba4e
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 101 deletions.
12 changes: 6 additions & 6 deletions pkg/devfile/adapters/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ type Storage struct {

// BuildParameters is a struct containing the parameters to be used when building the image for a devfile component
type BuildParameters struct {
Path string // Path refers to the parent folder containing the source code to push up to a component
DockerfileBytes []byte // DockerfileBytes is the contents of the project Dockerfile in bytes
EnvSpecificInfo envinfo.EnvSpecificInfo // EnvSpecificInfo contains infomation of env.yaml file
Tag string // Tag refers to the image tag of the image being built
Credentials string // Credentials refers to the path to the dockerconfig file containing external registry credentials
IgnoredFiles []string // IgnoredFiles is the list of files to not push up to a component
Path string // Path refers to the parent folder containing the source code to push up to a component
DockerfileBytes []byte // DockerfileBytes is the contents of the project Dockerfile in bytes
EnvSpecificInfo envinfo.EnvSpecificInfo // EnvSpecificInfo contains infomation of env.yaml file
Tag string // Tag refers to the image tag of the image being built
DockerConfigJSONFilename string // Credentials refers to the path to the dockerconfig file containing external registry credentials
IgnoredFiles []string // IgnoredFiles is the list of files to not push up to a component
}

// DeployParameters is a struct containing the parameters to be used when building the image for a devfile component
Expand Down
226 changes: 151 additions & 75 deletions pkg/devfile/adapters/kubernetes/component/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
"syscall"
"time"

"github.com/mitchellh/go-homedir"
"github.com/openshift/odo/pkg/exec"
"github.com/openshift/odo/pkg/secret"
"github.com/openshift/odo/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -48,6 +48,7 @@ import (

const (
DeployWaitTimeout = 60 * time.Second
regcredName = "regcred"
)

// New instantiantes a component adapter
Expand Down Expand Up @@ -82,94 +83,152 @@ type Adapter struct {

const dockerfilePath string = "Dockerfile"

var runAsUser = int64(1000)

func (a Adapter) generateBuildContainer(containerName string, dockerfileBytes []byte, imageTag string) corev1.Container {
// buildImage := "gcr.io/kaniko-project/executor:latest"
buildImage := "docker.io/busybox:latest"

// TODO(Optional): Init container before the buildah bud to copy over the files.

command := []string{}
commandArgs := []string{"--dockerfile=/kaniko/build-context/Dockerfile",
"--context=dir:///kaniko/build-context",
"--destination=" + imageTag,
"--skip-tls-verify"}
/*
command := []string{}
commandArgs := []string{"--dockerfile=/kaniko/build-context/Dockerfile",
"--context=dir:///kaniko/build-context",
"--destination=" + imageTag,
"--skip-tls-verify"}
*/
/*
envVars := []corev1.EnvVar{
{Name: "DOCKER_CONFIG", Value: "/kaniko/.docker"},
{Name: "AWS_ACCESS_KEY_ID", Value: "NOT_SET"},
{Name: "AWS_SECRET_KEY", Value: "NOT_SET"},
}
*/

envVars := []corev1.EnvVar{
{Name: "DOCKER_CONFIG", Value: "/kaniko/.docker"},
{Name: "AWS_ACCESS_KEY_ID", Value: "NOT_SET"},
{Name: "AWS_SECRET_KEY", Value: "NOT_SET"},
}
//isPrivileged := false

isPrivileged := false
//resourceReqs := corev1.ResourceRequirements{}

resourceReqs := corev1.ResourceRequirements{}
// container := kclient.GenerateContainer(containerName, buildImage, isPrivileged, command, commandArgs, envVars, resourceReqs, nil)

container := kclient.GenerateContainer(containerName, buildImage, isPrivileged, command, commandArgs, envVars, resourceReqs, nil)
container := kclient.GenerateContainer(containerName,
//"busybox",
"nginx",
true, // isPrivileged
[]string{},
// []string{"while true; do echo \"x\"; sleep 5; done"},

[]string{}, // command args
[]corev1.EnvVar{}, corev1.ResourceRequirements{},
nil) // ports

container.VolumeMounts = []corev1.VolumeMount{
// {Name: "destination", MountPath: "/data"},
{Name: "build-context", MountPath: "/kaniko/build-context"},
{Name: "kaniko-secret", MountPath: "/kaniko/.docker"},
}
if container.SecurityContext == nil {
container.SecurityContext = &corev1.SecurityContext{}
}

/*
if container.SecurityContext == nil {
container.SecurityContext = &corev1.SecurityContext{}
}
*/
// priv := true
// container.SecurityContext.Privileged = &priv
return *container
}

func (a Adapter) generateInitContainer(initContainerName string) corev1.Container {

initImage := "ubuntu"
command := []string{}
commandArgs := []string{"/bin/sh", "-c", "while true; do sleep 1"}
//initImage := "ubuntu"
//command := []string{}
//commandArgs := []string{"/bin/sh", "-c", "while true; do sleep 1"}
// commandArgs := []string{}
isPrivileged := false
envVars := []corev1.EnvVar{}
resourceReqs := corev1.ResourceRequirements{}

container := kclient.GenerateContainer(initContainerName, initImage, isPrivileged, command, commandArgs, envVars, resourceReqs, nil)

container.VolumeMounts = []corev1.VolumeMount{
{Name: "build-context", MountPath: "/kaniko/build-context"},
}
//isPrivileged := false
//envVars := []corev1.EnvVar{}
//resourceReqs := corev1.ResourceRequirements{}

container := kclient.GenerateContainer(initContainerName,
//"busybox",
"ngnix",
true, // privileged
// []string{"while true; do echo \"x\"; sleep 5; done"},
[]string{}, // comand
[]string{}, // comand args

[]corev1.EnvVar{}, corev1.ResourceRequirements{},
nil) // ports

/*
container.VolumeMounts = []corev1.VolumeMount{
{Name: "source", MountPath: "/src"},
{Name: "destination", MountPath: "/dst"},
}
*/

return *container
}

func (a Adapter) createBuildDeployment(labels map[string]string, container, initContainer corev1.Container) (err error) {

objectMeta := kclient.CreateObjectMeta(a.ComponentName, a.Client.Namespace, labels, nil)
podTemplateSpec := kclient.GeneratePodTemplateSpec(objectMeta, []corev1.Container{container})

buildContextVolume := corev1.Volume{
Name: "build-context",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
}

kanikoSecretVolume := corev1.Volume{
Name: "kaniko-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "registry-credentials",
Items: []corev1.KeyToPath{
{
Key: ".dockerconfigjson",
Path: "config.json",
//podTemplateSpec := kclient.GeneratePodTemplateSpec(objectMeta, []corev1.Container{container})
//hostPathType := corev1.HostPathDirectoryOrCreate
//hostPathType := corev1.HostPathFileOrCreate

podTemplateSpec := &corev1.PodTemplateSpec{
ObjectMeta: objectMeta,
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{initContainer},
Containers: []corev1.Container{container},
Volumes: []corev1.Volume{
{Name: "kaniko-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: regcredName,
Items: []corev1.KeyToPath{
{
Key: ".dockerconfigjson",
Path: "config.json",
},
},
},
},
},
{Name: "build-context",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
},
},
}

podTemplateSpec.Spec.Volumes = append(podTemplateSpec.Spec.Volumes, buildContextVolume)
podTemplateSpec.Spec.Volumes = append(podTemplateSpec.Spec.Volumes, kanikoSecretVolume)
podTemplateSpec.Spec.InitContainers = []corev1.Container{initContainer}
/*
buildContextVolume := corev1.Volume{
Name: "build-context",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
}
kanikoSecretVolume := corev1.Volume{
Name: "kaniko-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: regcredName,
Items: []corev1.KeyToPath{
{
Key: ".dockerconfigjson",
Path: "config.json",
},
},
},
},
}
podTemplateSpec.Spec.Volumes = append(podTemplateSpec.Spec.Volumes, buildContextVolume)
podTemplateSpec.Spec.Volumes = append(podTemplateSpec.Spec.Volumes, kanikoSecretVolume)
podTemplateSpec.Spec.InitContainers = []corev1.Container{initContainer}
*/
// podTemplateSpec.Spec.SecurityContext.RunAsUser = &runAsUser
// if podTemplateSpec.Spec.SecurityContext == nil {
// podTemplateSpec.Spec.SecurityContext = &corev1.PodSecurityContext{}
Expand Down Expand Up @@ -319,13 +378,22 @@ func (a Adapter) Build(parameters common.BuildParameters) (err error) {
func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error) {

NamespacedName := types.NamespacedName{
Name: "registry-credentials",
Name: regcredName,
Namespace: parameters.EnvSpecificInfo.GetNamespace(),
}

dockerConfigBytes, err := util.LoadFileIntoMemory(parameters.Credentials)
dockerSecret, err := secret.CreateDockerConfigSecret(NamespacedName, dockerConfigBytes)
authJSONPath, err := homedir.Expand(parameters.DockerConfigJSONFilename)
if err != nil {
return fmt.Errorf("failed to generate path to file: %v", err)
}

f, err := os.Open(authJSONPath)
if err != nil {
return fmt.Errorf("failed to read Docker config %#v : %s", authJSONPath, err)
}
defer f.Close()

dockerSecret, err := secret.CreateDockerConfigSecret(NamespacedName, f)
if err != nil {
return err
}
Expand All @@ -335,19 +403,23 @@ func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error)
Version: "v1",
Kind: "Secret",
}

gvr := schema.GroupVersionResource{Group: gvk.Group, Version: gvk.Version, Resource: strings.ToLower(gvk.Kind + "s")}
dockerSecretMap, err := runtimeUnstructured.DefaultUnstructuredConverter.ToUnstructured(dockerSecret)
dockerSecretByteArray, err := json.Marshal(dockerSecretMap)
var dockerSecretUnstructured *unstructured.Unstructured
dockerErr := json.Unmarshal(dockerSecretByteArray, &dockerSecretUnstructured)
if dockerErr != nil {
return dockerErr
err = json.Unmarshal(dockerSecretByteArray, &dockerSecretUnstructured)
if err != nil {
return err
}
_, dockerSecreteError := a.Client.DynamicClient.Resource(gvr).Namespace(NamespacedName.Namespace).Create(dockerSecretUnstructured, metav1.CreateOptions{})
_, err = a.Client.DynamicClient.Resource(gvr).Namespace(NamespacedName.Namespace).Create(dockerSecretUnstructured, metav1.CreateOptions{})

if dockerSecreteError != nil {
return dockerSecreteError
if err != nil {
if errors.Cause(err).Error() != "secrets \""+regcredName+"\" already exists" {
return err
}
}

containerName := a.ComponentName + "-kaniko-build-container"
initContainerName := "kaniko-init"
buildContainer := a.generateBuildContainer(containerName, parameters.DockerfileBytes, parameters.Tag)
Expand All @@ -362,18 +434,19 @@ func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error)
}

// Delete deployment
defer func() {
derr := a.Delete(labels)
if err == nil {
err = errors.Wrapf(derr, "failed to delete build step for component with name: %s", a.ComponentName)
}

// rerr := os.Remove(parameters.DockerfilePath)
// if err == nil {
// err = errors.Wrapf(rerr, "failed to delete %s", parameters.DockerfilePath)
// }
}()
/*
defer func() {
derr := a.Delete(labels)
if err == nil {
err = errors.Wrapf(derr, "failed to delete build step for component with name: %s", a.ComponentName)
}
// rerr := os.Remove(parameters.DockerfilePath)
// if err == nil {
// err = errors.Wrapf(rerr, "failed to delete %s", parameters.DockerfilePath)
// }
}()
*/
// _, err = a.Client.WaitForDeploymentRollout(a.ComponentName)
// if err != nil {
// return errors.Wrap(err, "error while waiting for deployment rollout")
Expand All @@ -391,6 +464,8 @@ func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error)
}

pod, err := a.Client.WaitAndGetPod(watchOptions, corev1.PodPending, "Waiting for component to start in waitAndGetComponentPod", false)
// pod, err := a.Client.WaitAndGetPod(watchOptions, corev1.PodRunning, "Waiting for component to start in waitAndGetComponentPod", false)

if err != nil {
return errors.Wrapf(err, "error while waiting for pod %s", podSelector)
}
Expand All @@ -403,6 +478,7 @@ func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error)
// Get a sync adapter. Check if project files have changed and sync accordingly
syncAdapter := sync.New(a.AdapterContext, &a.Client)
compInfo := common.ComponentInfo{
//ContainerName: containerName,
ContainerName: initContainerName,
PodName: pod.GetName(),
}
Expand All @@ -416,7 +492,7 @@ func (a Adapter) BuildWithKaniko(parameters common.BuildParameters) (err error)
}
log.Spinner("~~~~~~~~~~~~ BEFORE inject ~~~~~~~~~~~~~~~~~")

destinationDirectory := "/tmp/build-context"
destinationDirectory := "/kaniko/build-context"
klog.V(4).Infof("Copying files to pod")
err = a.Client.ExtractProjectToComponent(compInfo, destinationDirectory, syncFolder)
if err != nil {
Expand Down Expand Up @@ -634,7 +710,7 @@ func (a Adapter) Deploy(parameters common.DeployParameters) (err error) {

// Need to wait for a second to give the server time to create the artifacts
// TODO: Replace wait with a wait for object to be created
time.Sleep(2 * time.Second)
//time.Sleep(2 * time.Second)

fullURL := ""
urlList, err := url.List(client, &config.LocalConfigInfo{}, "", applicationName)
Expand Down
20 changes: 10 additions & 10 deletions pkg/odo/cli/component/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ type DeployOptions struct {
ignores []string
EnvSpecificInfo *envinfo.EnvSpecificInfo

DevfilePath string
devObj devfileParser.DevfileObj
DockerfileURL string
DockerfileBytes []byte
namespace string
tag string
credentials string
ManifestSource []byte
DeploymentPort int
DevfilePath string
devObj devfileParser.DevfileObj
DockerfileURL string
DockerfileBytes []byte
namespace string
tag string
dockerConfigJSONFilename string
ManifestSource []byte
DeploymentPort int

*genericclioptions.Context
}
Expand Down Expand Up @@ -215,8 +215,8 @@ func NewCmdDeploy(name, fullName string) *cobra.Command {

// enable devfile flag if experimental mode is enabled
deployCmd.Flags().StringVar(&do.tag, "tag", "", "Tag used to build the image")
deployCmd.Flags().StringVar(&do.credentials, "credentials", "", "dockerconfig credentials used to push image to external registry")
deployCmd.Flags().StringSliceVar(&do.ignores, "ignore", []string{}, "Files or folders to be ignored via glob expressions.")
deployCmd.Flags().StringVar(&do.dockerConfigJSONFilename, "dockerconfigjson", "~/.docker/config.json", "Filepath to config.json which authenticates the image push to the desired image registry ")

//Adding `--project` flag
projectCmd.AddProjectFlag(deployCmd)
Expand Down
Loading

0 comments on commit f36ba4e

Please sign in to comment.