From 61ee0d8746597f5cd0e80194221734bb9e5eb8eb Mon Sep 17 00:00:00 2001 From: rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Mon, 1 Aug 2022 18:39:44 +0800 Subject: [PATCH 1/5] Support to convert between k8s podtemplate and Jenkins --- pkg/k8s/cloud.go | 226 ++++++++++++++++++++++++++ pkg/k8s/cloud_test.go | 128 +++++++++++++++ pkg/k8s/go.mod | 27 +++ pkg/k8s/go.sum | 111 +++++++++++++ pkg/k8s/testdata/casc.yaml | 86 ++++++++++ pkg/k8s/testdata/cloud-k8s.yaml | 47 ++++++ pkg/k8s/testdata/k8s-podtemplate.yaml | 41 +++++ pkg/k8s/testdata/result-casc.yaml | 117 +++++++++++++ 8 files changed, 783 insertions(+) create mode 100644 pkg/k8s/cloud.go create mode 100644 pkg/k8s/cloud_test.go create mode 100644 pkg/k8s/go.mod create mode 100644 pkg/k8s/go.sum create mode 100644 pkg/k8s/testdata/casc.yaml create mode 100644 pkg/k8s/testdata/cloud-k8s.yaml create mode 100644 pkg/k8s/testdata/k8s-podtemplate.yaml create mode 100644 pkg/k8s/testdata/result-casc.yaml diff --git a/pkg/k8s/cloud.go b/pkg/k8s/cloud.go new file mode 100644 index 0000000..9884617 --- /dev/null +++ b/pkg/k8s/cloud.go @@ -0,0 +1,226 @@ +package k8s + +import ( + "fmt" + "reflect" + "strings" + + unstructured "github.com/linuxsuren/unstructured/pkg" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/yaml" +) + +// JenkinsConfig represents a Jenkins configuration-as-code object +type JenkinsConfig struct { + Config []byte +} + +func (c *JenkinsConfig) GetConfigAsString() string { + return string(c.Config) +} + +// AddPodTemplate adds a PodTemplate to the Jenkins cloud config +func (c *JenkinsConfig) AddPodTemplate(podTemplate *v1.PodTemplate) (err error) { + casc := map[string]interface{}{} + if err = yaml.Unmarshal(c.Config, &casc); err != nil { + err = fmt.Errorf("failed to unmarshal YAML to map structure, error: %v", err) + return + } + + var templatesObj interface{} + var ok bool + if templatesObj, ok, err = unstructured.NestedField(casc, "jenkins", "clouds[0]", "kubernetes", "templates"); !ok { + err = fmt.Errorf("failed to find jenkins.cloud[0]") + } else if err != nil { + return + } + + var targetPodTemplate JenkinsPodTemplate + if targetPodTemplate, err = ConvertToJenkinsPodTemplate(podTemplate); err != nil { + return + } + + var templates []interface{} + if templates, ok = templatesObj.([]interface{}); ok { + templates = append(templates, targetPodTemplate) + } + + if err = unstructured.SetNestedField(casc, templates, "jenkins", "clouds[0]", "kubernetes", "templates"); err != nil { + return + } + + if c.Config, err = yaml.Marshal(casc); err != nil { + return + } + return +} + +func ConvertToJenkinsPodTemplate(podTemplate *v1.PodTemplate) (target JenkinsPodTemplate, err error) { + target.Name = podTemplate.Name + target.Namespace = podTemplate.Namespace + target.Label = podTemplate.Name + target.NodeUsageMode = "EXCLUSIVE" + + // make sure the annotations are not empty + if podTemplate.Annotations == nil { + podTemplate.Annotations = map[string]string{} + } + annotations := podTemplate.Annotations + + containers := podTemplate.Template.Spec.Containers + containersCount := len(containers) + if containersCount > 0 { + target.Containers = make([]Container, containersCount) + + for i, container := range containers { + name := container.Name + target.Containers[i] = Container{ + Name: name, + Image: container.Image, + Command: strings.Join(container.Command, " "), + Args: strings.Join(container.Args, " "), + ResourceLimitCPU: annotations[fmt.Sprintf("container.%s.resourceLimitCpu", name)], + ResourceLimitMemory: annotations[fmt.Sprintf("container.%s.resourceLimitMemory", name)], + ResourceRequestCPU: annotations[fmt.Sprintf("container.%s.resourceRequestCpu", name)], + ResourceRequestMemory: annotations[fmt.Sprintf("container.%s.resourceRequestMemory", name)], + YAML: annotations[fmt.Sprintf("container.%s.yaml", name)], + TtyEnabled: true, + } + } + + container := containers[0] + for _, volMount := range container.VolumeMounts { + for _, vol := range podTemplate.Template.Spec.Volumes { + if vol.Name == volMount.Name && vol.HostPath != nil { + target.Volumes = append(target.Volumes, Volume{ + HostPathVolume{ + HostPath: vol.HostPath.Path, + MountPath: volMount.MountPath, + }, + }) + break + } + } + } + } + return +} + +// RemovePodTemplate removes a PodTemplate from the Jenkins cloud config +func (c *JenkinsConfig) RemovePodTemplate(name string) (err error) { + casc := map[string]interface{}{} + if err = yaml.Unmarshal(c.Config, &casc); err != nil { + err = fmt.Errorf("failed to unmarshal YAML to map structure, error: %v", err) + return + } + + var templatesObj interface{} + var ok bool + if templatesObj, ok, err = unstructured.NestedField(casc, "jenkins", "clouds[0]", "kubernetes", "templates"); !ok { + err = fmt.Errorf("failed to find jenkins.cloud[0]") + } else if err != nil { + return + } + + var templateArray []interface{} + if templateArray, ok = templatesObj.([]interface{}); ok { + for i, templateObj := range templateArray { + var template map[string]interface{} + if template, ok = templateObj.(map[string]interface{}); ok { + fmt.Println("=====", template["name"], reflect.TypeOf(template["name"]), name) + if template["name"].(string) == name { + if i == len(template)-1 { + templateArray = templateArray[0:i] + } else { + templateArray = append(templateArray[0:i], templateArray[i+1:]...) + } + break + } + } + } + } + + if err = unstructured.SetNestedField(casc, templateArray, "jenkins", "clouds[0]", "kubernetes", "templates"); err != nil { + return + } + + if c.Config, err = yaml.Marshal(casc); err != nil { + return + } + return +} + +func (c *JenkinsConfig) getJSON() (data []byte, err error) { + data, err = yaml.YAMLToJSON(c.Config) + return +} + +// CloudAgent represents a Jenkins cloud agent +type CloudAgent struct { + Kubernetes KubernetesCloud `json:"kubernetes"` +} + +// KubernetesCloud represents a Kubernetes connection in Jenkins +type KubernetesCloud struct { + Name string `json:"name"` + ServerURL string `json:"serverUrl"` + SkipTLSVerify bool `json:"skipTlsVerify"` + Namespace string `json:"namespace"` + CredentialsID string `json:"credentialsId"` + JenkinsURL string `json:"jenkinsUrl"` + JenkinsTunnel string `json:"jenkinsTunnel"` + ContainerCapStr string `json:"containerCapStr"` + ConnectTimeout string `json:"connectTimeout"` + ReadTimeout string `json:"readTimeout"` + MaxRequestsPerhHostStr string `json:"maxRequestsPerhHostStr"` + Templates []JenkinsPodTemplate `json:"templates"` +} + +// JenkinsPodTemplate represents the PodTemplate that defined in Jenkins +type JenkinsPodTemplate struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Label string `json:"label"` + NodeUsageMode string `json:"nodeUsageMode"` + IdleMinutes int `json:"idleMinutes"` + Containers []Container `json:"containers"` + Volumes []Volume `json:"volumes"` +} + +type Volume struct { + HostPathVolume HostPathVolume `json:"hostPathVolume"` +} + +// Container represents the container that defined in Jenkins +type Container struct { + Name string `json:"name"` + Image string `json:"image"` + Command string `json:"command"` + Args string `json:"args"` + TtyEnabled bool `json:"ttyEnabled"` + Privileged bool `json:"privileged"` + ResourceRequestCPU string `json:"resourceRequestCpu"` + ResourceLimitCPU string `json:"resourceLimitCpu"` + ResourceRequestMemory string `json:"resourceRequestMemory"` + ResourceLimitMemory string `json:"resourceLimitMemory"` + WorkspaceVolume WorkspaceVolume `json:"workspaceVolume"` + Volumes []HostPathVolume `json:"volumes"` + // YAML is the YAML format for merging into the whole PodTemplate + YAML string `json:"yaml"` +} + +// WorkspaceVolume is the volume of the Jenkins agent workspace +type WorkspaceVolume struct { + EmptyDirWorkspaceVolume EmptyDirWorkspaceVolume `json:"emptyDirWorkspaceVolume"` +} + +// EmptyDirWorkspaceVolume is an empty dir type of workspace volume +type EmptyDirWorkspaceVolume struct { + Memory bool `json:"memory"` +} + +// HostPathVolume represents a host path volume +type HostPathVolume struct { + HostPath string `json:"hostPath"` + MountPath string `json:"mountPath"` +} diff --git a/pkg/k8s/cloud_test.go b/pkg/k8s/cloud_test.go new file mode 100644 index 0000000..6d1e283 --- /dev/null +++ b/pkg/k8s/cloud_test.go @@ -0,0 +1,128 @@ +package k8s + +import ( + "io/ioutil" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/yaml" +) + +func TestJenkinsConfig_AddPodTemplate(t *testing.T) { + type fields struct { + Config []byte + } + type args struct { + podTemplate *v1.PodTemplate + } + tests := []struct { + name string + fields fields + args args + expectResult string + wantErr bool + }{{ + name: "normal", + fields: fields{Config: readFile("testdata/casc.yaml")}, + args: args{podTemplate: readPodTemplate("testdata/k8s-podtemplate.yaml")}, + expectResult: "testdata/result-casc.yaml", + wantErr: false, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &JenkinsConfig{ + Config: tt.fields.Config, + } + if err := c.AddPodTemplate(tt.args.podTemplate); (err != nil) != tt.wantErr { + t.Errorf("AddPodTemplate() error = %v, wantErr %v", err, tt.wantErr) + } + + assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + }) + } +} + +func TestJenkinsConfig_RemovePodTemplate(t *testing.T) { + type fields struct { + Config []byte + } + type args struct { + podTemplate string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + expectResult string + }{{ + name: "normal", + fields: fields{Config: readFile("testdata/result-casc.yaml")}, + args: args{podTemplate: "base"}, + expectResult: "testdata/casc.yaml", + wantErr: false, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &JenkinsConfig{ + Config: tt.fields.Config, + } + if err := c.RemovePodTemplate(tt.args.podTemplate); (err != nil) != tt.wantErr { + t.Errorf("RemovePodTemplate() error = %v, wantErr %v", err, tt.wantErr) + } + assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + }) + } +} + +func readPodTemplate(file string) (result *v1.PodTemplate) { + result = &v1.PodTemplate{} + + data := readFile(file) + _ = yaml.Unmarshal(data, result) + return +} + +func readFile(file string) (data []byte) { + data, _ = ioutil.ReadFile(file) + return +} + +func readFileASString(file string) string { + return string(readFile(file)) +} + +func TestJenkinsConfig_getJSON(t *testing.T) { + type fields struct { + Config []byte + } + tests := []struct { + name string + fields fields + wantData []byte + wantErr bool + }{{ + name: "normal", + fields: fields{Config: []byte(`name: name +server: server`)}, + wantData: []byte(`{"name":"name","server":"server"}`), + wantErr: false, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &JenkinsConfig{ + Config: tt.fields.Config, + } + gotData, err := c.getJSON() + if (err != nil) != tt.wantErr { + t.Errorf("getJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotData, tt.wantData) { + t.Errorf("getJSON() gotData = %v, wantVal %v", gotData, tt.wantData) + } + }) + } +} diff --git a/pkg/k8s/go.mod b/pkg/k8s/go.mod new file mode 100644 index 0000000..b3b0277 --- /dev/null +++ b/pkg/k8s/go.mod @@ -0,0 +1,27 @@ +module github.comm/jenkins-zh/jenkins-client/pkg/k8s + +go 1.18 + +require ( + github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb + github.com/stretchr/testify v1.4.0 + k8s.io/api v0.18.6 + sigs.k8s.io/yaml v1.2.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gogo/protobuf v1.3.1 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/json-iterator/go v1.1.8 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect + golang.org/x/text v0.3.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect + k8s.io/apimachinery v0.18.6 // indirect + k8s.io/klog v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect +) diff --git a/pkg/k8s/go.sum b/pkg/k8s/go.sum new file mode 100644 index 0000000..b34121c --- /dev/null +++ b/pkg/k8s/go.sum @@ -0,0 +1,111 @@ +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb h1:ri9L96uTkrt35nOo0ktQRQ6ZT7oOy8YtAzmzf6VzX6E= +github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.18.6 h1:osqrAXbOQjkKIWDTjrqxWQ3w0GkKb1KA1XkUGHHYpeE= +k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= +k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag= +k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/pkg/k8s/testdata/casc.yaml b/pkg/k8s/testdata/casc.yaml new file mode 100644 index 0000000..b84c394 --- /dev/null +++ b/pkg/k8s/testdata/casc.yaml @@ -0,0 +1,86 @@ +jenkins: + clouds: + - kubernetes: + connectTimeout: "60" + containerCapStr: "4" + credentialsId: k8s-service-account + jenkinsTunnel: devops-jenkins-agent.kubesphere-devops-system:50000 + jenkinsUrl: http://devops-jenkins.kubesphere-devops-system:80 + maxRequestsPerHostStr: "32" + name: kubernetes + namespace: kubesphere-devops-worker + readTimeout: "60" + serverUrl: https://kubernetes.default + skipTlsVerify: true + templates: + - containers: + - args: "" + command: cat + image: kubesphere/builder-go:v3.2.0 + name: go + privileged: false + resourceLimitCpu: 4000m + resourceLimitMemory: 8192Mi + resourceRequestCpu: 100m + resourceRequestMemory: 100Mi + ttyEnabled: true + - args: ^${computer.jnlpmac} ^${computer.name} + command: jenkins-slave + image: jenkins/jnlp-slave:3.27-1 + name: jnlp + resourceLimitCpu: 500m + resourceLimitMemory: 1536Mi + resourceRequestCpu: 50m + resourceRequestMemory: 400Mi + idleMinutes: 0 + label: go + name: go + namespace: kubesphere-devops-worker + nodeUsageMode: EXCLUSIVE + volumes: + - hostPathVolume: + hostPath: /var/run/docker.sock + mountPath: /var/run/docker.sock + - hostPathVolume: + hostPath: /var/data/jenkins_go_cache + mountPath: /home/jenkins/go/pkg + - hostPathVolume: + hostPath: /var/data/jenkins_sonar_cache + mountPath: /root/.sonar/cache + workspaceVolume: + emptyDirWorkspaceVolume: + memory: false + yaml: "" + disableRememberMe: true + mode: EXCLUSIVE + numExecutors: 0 + scmCheckoutRetryCount: 2 + securityRealm: + ldap: + configurations: + - displayNameAttributeName: uid + groupSearchBase: ou=Groups + groupSearchFilter: (&(objectClass=posixGroup)(cn={0})) + inhibitInferRootDN: false + mailAddressAttributeName: mail + managerDN: cn=admin,dc=kubesphere,dc=io + managerPasswordSecret: admin + rootDN: dc=kubesphere,dc=io + server: ldap://openldap.kubesphere-system.svc:389 + userSearch: (&(objectClass=inetOrgPerson)(|(uid={0})(mail={0}))) + userSearchBase: ou=Users + disableMailAddressResolver: false + disableRolePrefixing: true +unclassified: + gitLabServers: + servers: + - name: https://gitlab.com + serverUrl: https://gitlab.com + kubespheretokenauthglobalconfiguration: + cacheConfiguration: + size: 20 + ttl: 300 + enabled: true + server: http://devops-apiserver.kubesphere-devops-system:9090/ + location: + url: jenkins.devops.kubesphere.local diff --git a/pkg/k8s/testdata/cloud-k8s.yaml b/pkg/k8s/testdata/cloud-k8s.yaml new file mode 100644 index 0000000..6b707c6 --- /dev/null +++ b/pkg/k8s/testdata/cloud-k8s.yaml @@ -0,0 +1,47 @@ +name: "kubernetes" +serverUrl: "https://kubernetes.default" +skipTlsVerify: true +namespace: "kubesphere-devops-worker" +credentialsId: "k8s-service-account" +jenkinsUrl: "http://devops-jenkins.kubesphere-devops-system:80" +jenkinsTunnel: "devops-jenkins-agent.kubesphere-devops-system:50000" +containerCapStr: "4" +connectTimeout: "60" +readTimeout: "60" +maxRequestsPerHostStr: "32" +templates: + - name: "base" + namespace: "kubesphere-devops-worker" + label: "base" + nodeUsageMode: "NORMAL" + idleMinutes: 0 + containers: + - name: "base" + image: "kubesphere/builder-base:v3.2.0" + command: "cat" + args: "" + ttyEnabled: true + privileged: false + resourceRequestCpu: "100m" + resourceLimitCpu: "4000m" + resourceRequestMemory: "100Mi" + resourceLimitMemory: "8192Mi" + - name: "jnlp" + image: "jenkins/jnlp-slave:3.27-1" + command: "jenkins-slave" + args: "^${computer.jnlpmac} ^${computer.name}" + resourceRequestCpu: "50m" + resourceLimitCpu: "500m" + resourceRequestMemory: "400Mi" + resourceLimitMemory: "1536Mi" + workspaceVolume: + emptyDirWorkspaceVolume: + memory: false + volumes: + - hostPathVolume: + hostPath: "/var/run/docker.sock" + mountPath: "/var/run/docker.sock" + - hostPathVolume: + hostPath: "/var/data/jenkins_sonar_cache" + mountPath: "/root/.sonar/cache" + yaml: "spec:\r\n affinity:\r\n nodeAffinity:\r\n preferredDuringSchedulingIgnoredDuringExecution:\r\n - weight: 1\r\n preference:\r\n matchExpressions:\r\n - key: node-role.kubernetes.io/worker\r\n operator: In\r\n values:\r\n - ci\r\n tolerations:\r\n - key: \"node.kubernetes.io/ci\"\r\n operator: \"Exists\"\r\n effect: \"NoSchedule\"\r\n - key: \"node.kubernetes.io/ci\"\r\n operator: \"Exists\"\r\n effect: \"PreferNoSchedule\"\r\n containers:\r\n - name: \"base\"\r\n resources:\r\n requests:\r\n ephemeral-storage: \"1Gi\"\r\n limits:\r\n ephemeral-storage: \"10Gi\"\r\n securityContext:\r\n fsGroup: 1000\r\n " diff --git a/pkg/k8s/testdata/k8s-podtemplate.yaml b/pkg/k8s/testdata/k8s-podtemplate.yaml new file mode 100644 index 0000000..8b31489 --- /dev/null +++ b/pkg/k8s/testdata/k8s-podtemplate.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: PodTemplate +metadata: + name: base + namespace: default + annotations: + container.base.resourceRequestCpu: "100m" + container.base.resourceLimitCpu: "4000m" + container.base.resourceRequestMemory: "100Mi" + container.base.resourceLimitMemory: "8192Mi" + container.base.yaml: "fake" + container.jnlp.resourceRequestCpu: "50m" + container.jnlp.resourceLimitCpu: "500m" + container.jnlp.resourceRequestMemory: "400Mi" + container.jnlp.resourceLimitMemory: "1536Mi" +template: + metadata: + name: base + spec: + volumes: + - name: docker + hostPath: + path: /var/run/docker.sock + - name: gocache + hostPath: + path: /var/data/jenkins_go_cache + - name: sonarcache + hostPath: + path: /var/data/jenkins_sonar_cache + containers: + - name: base + image: kubesphere/builder-base:v3.2.0 + command: ["cat"] + args: [""] + volumeMounts: + - name: docker + mountPath: /var/run/docker.sock + - name: gocache + mountPath: /home/jenkins/go/pkg + - name: sonarcache + mountPath: /root/.sonar/cache diff --git a/pkg/k8s/testdata/result-casc.yaml b/pkg/k8s/testdata/result-casc.yaml new file mode 100644 index 0000000..09cfad5 --- /dev/null +++ b/pkg/k8s/testdata/result-casc.yaml @@ -0,0 +1,117 @@ +jenkins: + clouds: + - kubernetes: + connectTimeout: "60" + containerCapStr: "4" + credentialsId: k8s-service-account + jenkinsTunnel: devops-jenkins-agent.kubesphere-devops-system:50000 + jenkinsUrl: http://devops-jenkins.kubesphere-devops-system:80 + maxRequestsPerHostStr: "32" + name: kubernetes + namespace: kubesphere-devops-worker + readTimeout: "60" + serverUrl: https://kubernetes.default + skipTlsVerify: true + templates: + - containers: + - args: "" + command: cat + image: kubesphere/builder-go:v3.2.0 + name: go + privileged: false + resourceLimitCpu: 4000m + resourceLimitMemory: 8192Mi + resourceRequestCpu: 100m + resourceRequestMemory: 100Mi + ttyEnabled: true + - args: ^${computer.jnlpmac} ^${computer.name} + command: jenkins-slave + image: jenkins/jnlp-slave:3.27-1 + name: jnlp + resourceLimitCpu: 500m + resourceLimitMemory: 1536Mi + resourceRequestCpu: 50m + resourceRequestMemory: 400Mi + idleMinutes: 0 + label: go + name: go + namespace: kubesphere-devops-worker + nodeUsageMode: EXCLUSIVE + volumes: + - hostPathVolume: + hostPath: /var/run/docker.sock + mountPath: /var/run/docker.sock + - hostPathVolume: + hostPath: /var/data/jenkins_go_cache + mountPath: /home/jenkins/go/pkg + - hostPathVolume: + hostPath: /var/data/jenkins_sonar_cache + mountPath: /root/.sonar/cache + workspaceVolume: + emptyDirWorkspaceVolume: + memory: false + yaml: "" + - containers: + - args: "" + command: cat + image: kubesphere/builder-base:v3.2.0 + name: base + privileged: false + resourceLimitCpu: 4000m + resourceLimitMemory: 8192Mi + resourceRequestCpu: 100m + resourceRequestMemory: 100Mi + ttyEnabled: true + volumes: null + workspaceVolume: + emptyDirWorkspaceVolume: + memory: false + yaml: fake + idleMinutes: 0 + label: base + name: base + namespace: default + nodeUsageMode: EXCLUSIVE + volumes: + - hostPathVolume: + hostPath: /var/run/docker.sock + mountPath: /var/run/docker.sock + - hostPathVolume: + hostPath: /var/data/jenkins_go_cache + mountPath: /home/jenkins/go/pkg + - hostPathVolume: + hostPath: /var/data/jenkins_sonar_cache + mountPath: /root/.sonar/cache + disableRememberMe: true + mode: EXCLUSIVE + numExecutors: 0 + scmCheckoutRetryCount: 2 + securityRealm: + ldap: + configurations: + - displayNameAttributeName: uid + groupSearchBase: ou=Groups + groupSearchFilter: (&(objectClass=posixGroup)(cn={0})) + inhibitInferRootDN: false + mailAddressAttributeName: mail + managerDN: cn=admin,dc=kubesphere,dc=io + managerPasswordSecret: admin + rootDN: dc=kubesphere,dc=io + server: ldap://openldap.kubesphere-system.svc:389 + userSearch: (&(objectClass=inetOrgPerson)(|(uid={0})(mail={0}))) + userSearchBase: ou=Users + disableMailAddressResolver: false + disableRolePrefixing: true +unclassified: + gitLabServers: + servers: + - name: https://gitlab.com + serverUrl: https://gitlab.com + kubespheretokenauthglobalconfiguration: + cacheConfiguration: + size: 20 + ttl: 300 + enabled: true + server: http://devops-apiserver.kubesphere-devops-system:9090/ + location: + url: jenkins.devops.kubesphere.local From 4a2e10e10300f1979f623b11ec290599b0c9925b Mon Sep 17 00:00:00 2001 From: Rick Date: Tue, 2 Aug 2022 08:30:12 +0800 Subject: [PATCH 2/5] fix the lint issues --- pkg/k8s/cloud.go | 8 +++----- pkg/k8s/cloud_test.go | 34 ---------------------------------- pkg/k8s/go.mod | 19 +------------------ 3 files changed, 4 insertions(+), 57 deletions(-) diff --git a/pkg/k8s/cloud.go b/pkg/k8s/cloud.go index 9884617..4fdcd3b 100644 --- a/pkg/k8s/cloud.go +++ b/pkg/k8s/cloud.go @@ -15,6 +15,7 @@ type JenkinsConfig struct { Config []byte } +// GetConfigAsString returns the config data as string func (c *JenkinsConfig) GetConfigAsString() string { return string(c.Config) } @@ -55,6 +56,7 @@ func (c *JenkinsConfig) AddPodTemplate(podTemplate *v1.PodTemplate) (err error) return } +// ConvertToJenkinsPodTemplate converts a k8s style PodTemplate to a Jenkins style PodTemplate func ConvertToJenkinsPodTemplate(podTemplate *v1.PodTemplate) (target JenkinsPodTemplate, err error) { target.Name = podTemplate.Name target.Namespace = podTemplate.Namespace @@ -150,11 +152,6 @@ func (c *JenkinsConfig) RemovePodTemplate(name string) (err error) { return } -func (c *JenkinsConfig) getJSON() (data []byte, err error) { - data, err = yaml.YAMLToJSON(c.Config) - return -} - // CloudAgent represents a Jenkins cloud agent type CloudAgent struct { Kubernetes KubernetesCloud `json:"kubernetes"` @@ -187,6 +184,7 @@ type JenkinsPodTemplate struct { Volumes []Volume `json:"volumes"` } +// Volume represents the volume in kubernetes type Volume struct { HostPathVolume HostPathVolume `json:"hostPathVolume"` } diff --git a/pkg/k8s/cloud_test.go b/pkg/k8s/cloud_test.go index 6d1e283..b7c6ff0 100644 --- a/pkg/k8s/cloud_test.go +++ b/pkg/k8s/cloud_test.go @@ -2,7 +2,6 @@ package k8s import ( "io/ioutil" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -93,36 +92,3 @@ func readFile(file string) (data []byte) { func readFileASString(file string) string { return string(readFile(file)) } - -func TestJenkinsConfig_getJSON(t *testing.T) { - type fields struct { - Config []byte - } - tests := []struct { - name string - fields fields - wantData []byte - wantErr bool - }{{ - name: "normal", - fields: fields{Config: []byte(`name: name -server: server`)}, - wantData: []byte(`{"name":"name","server":"server"}`), - wantErr: false, - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := &JenkinsConfig{ - Config: tt.fields.Config, - } - gotData, err := c.getJSON() - if (err != nil) != tt.wantErr { - t.Errorf("getJSON() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotData, tt.wantData) { - t.Errorf("getJSON() gotData = %v, wantVal %v", gotData, tt.wantData) - } - }) - } -} diff --git a/pkg/k8s/go.mod b/pkg/k8s/go.mod index b3b0277..76124ba 100644 --- a/pkg/k8s/go.mod +++ b/pkg/k8s/go.mod @@ -1,4 +1,4 @@ -module github.comm/jenkins-zh/jenkins-client/pkg/k8s +module github.com/jenkins-zh/jenkins-client/pkg/k8s go 1.18 @@ -8,20 +8,3 @@ require ( k8s.io/api v0.18.6 sigs.k8s.io/yaml v1.2.0 ) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gogo/protobuf v1.3.1 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/json-iterator/go v1.1.8 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect - golang.org/x/text v0.3.2 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect - k8s.io/apimachinery v0.18.6 // indirect - k8s.io/klog v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect -) From 83ae216379d67dbbb0272949aa902d5f533fa1f1 Mon Sep 17 00:00:00 2001 From: rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Tue, 2 Aug 2022 18:51:42 +0800 Subject: [PATCH 3/5] Fix the wrong struture of podTemplate of yaml --- pkg/k8s/cloud.go | 39 +++++++++++++-------------- pkg/k8s/testdata/k8s-podtemplate.yaml | 18 ++++++------- pkg/k8s/testdata/result-casc.yaml | 8 +++--- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/pkg/k8s/cloud.go b/pkg/k8s/cloud.go index 4fdcd3b..2ae1ebf 100644 --- a/pkg/k8s/cloud.go +++ b/pkg/k8s/cloud.go @@ -2,7 +2,6 @@ package k8s import ( "fmt" - "reflect" "strings" unstructured "github.com/linuxsuren/unstructured/pkg" @@ -81,14 +80,14 @@ func ConvertToJenkinsPodTemplate(podTemplate *v1.PodTemplate) (target JenkinsPod Image: container.Image, Command: strings.Join(container.Command, " "), Args: strings.Join(container.Args, " "), - ResourceLimitCPU: annotations[fmt.Sprintf("container.%s.resourceLimitCpu", name)], - ResourceLimitMemory: annotations[fmt.Sprintf("container.%s.resourceLimitMemory", name)], - ResourceRequestCPU: annotations[fmt.Sprintf("container.%s.resourceRequestCpu", name)], - ResourceRequestMemory: annotations[fmt.Sprintf("container.%s.resourceRequestMemory", name)], - YAML: annotations[fmt.Sprintf("container.%s.yaml", name)], + ResourceLimitCPU: annotations[fmt.Sprintf("containers.%s.resourceLimitCpu", name)], + ResourceLimitMemory: annotations[fmt.Sprintf("containers.%s.resourceLimitMemory", name)], + ResourceRequestCPU: annotations[fmt.Sprintf("containers.%s.resourceRequestCpu", name)], + ResourceRequestMemory: annotations[fmt.Sprintf("containers.%s.resourceRequestMemory", name)], TtyEnabled: true, } } + target.YAML = annotations["containers.yaml"] container := containers[0] for _, volMount := range container.VolumeMounts { @@ -129,7 +128,6 @@ func (c *JenkinsConfig) RemovePodTemplate(name string) (err error) { for i, templateObj := range templateArray { var template map[string]interface{} if template, ok = templateObj.(map[string]interface{}); ok { - fmt.Println("=====", template["name"], reflect.TypeOf(template["name"]), name) if template["name"].(string) == name { if i == len(template)-1 { templateArray = templateArray[0:i] @@ -182,6 +180,9 @@ type JenkinsPodTemplate struct { IdleMinutes int `json:"idleMinutes"` Containers []Container `json:"containers"` Volumes []Volume `json:"volumes"` + // YAML is the YAML format for merging into the whole PodTemplate + YAML string `json:"yaml"` + WorkspaceVolume WorkspaceVolume `json:"workspaceVolume"` } // Volume represents the volume in kubernetes @@ -191,20 +192,16 @@ type Volume struct { // Container represents the container that defined in Jenkins type Container struct { - Name string `json:"name"` - Image string `json:"image"` - Command string `json:"command"` - Args string `json:"args"` - TtyEnabled bool `json:"ttyEnabled"` - Privileged bool `json:"privileged"` - ResourceRequestCPU string `json:"resourceRequestCpu"` - ResourceLimitCPU string `json:"resourceLimitCpu"` - ResourceRequestMemory string `json:"resourceRequestMemory"` - ResourceLimitMemory string `json:"resourceLimitMemory"` - WorkspaceVolume WorkspaceVolume `json:"workspaceVolume"` - Volumes []HostPathVolume `json:"volumes"` - // YAML is the YAML format for merging into the whole PodTemplate - YAML string `json:"yaml"` + Name string `json:"name"` + Image string `json:"image"` + Command string `json:"command"` + Args string `json:"args"` + TtyEnabled bool `json:"ttyEnabled"` + Privileged bool `json:"privileged"` + ResourceRequestCPU string `json:"resourceRequestCpu"` + ResourceLimitCPU string `json:"resourceLimitCpu"` + ResourceRequestMemory string `json:"resourceRequestMemory"` + ResourceLimitMemory string `json:"resourceLimitMemory"` } // WorkspaceVolume is the volume of the Jenkins agent workspace diff --git a/pkg/k8s/testdata/k8s-podtemplate.yaml b/pkg/k8s/testdata/k8s-podtemplate.yaml index 8b31489..48383bb 100644 --- a/pkg/k8s/testdata/k8s-podtemplate.yaml +++ b/pkg/k8s/testdata/k8s-podtemplate.yaml @@ -4,15 +4,15 @@ metadata: name: base namespace: default annotations: - container.base.resourceRequestCpu: "100m" - container.base.resourceLimitCpu: "4000m" - container.base.resourceRequestMemory: "100Mi" - container.base.resourceLimitMemory: "8192Mi" - container.base.yaml: "fake" - container.jnlp.resourceRequestCpu: "50m" - container.jnlp.resourceLimitCpu: "500m" - container.jnlp.resourceRequestMemory: "400Mi" - container.jnlp.resourceLimitMemory: "1536Mi" + containers.base.resourceRequestCpu: "100m" + containers.base.resourceLimitCpu: "4000m" + containers.base.resourceRequestMemory: "100Mi" + containers.base.resourceLimitMemory: "8192Mi" + containers.jnlp.resourceRequestCpu: "50m" + containers.jnlp.resourceLimitCpu: "500m" + containers.jnlp.resourceRequestMemory: "400Mi" + containers.jnlp.resourceLimitMemory: "1536Mi" + containers.yaml: "fake" template: metadata: name: base diff --git a/pkg/k8s/testdata/result-casc.yaml b/pkg/k8s/testdata/result-casc.yaml index 09cfad5..49a814b 100644 --- a/pkg/k8s/testdata/result-casc.yaml +++ b/pkg/k8s/testdata/result-casc.yaml @@ -63,10 +63,6 @@ jenkins: resourceRequestMemory: 100Mi ttyEnabled: true volumes: null - workspaceVolume: - emptyDirWorkspaceVolume: - memory: false - yaml: fake idleMinutes: 0 label: base name: base @@ -82,6 +78,10 @@ jenkins: - hostPathVolume: hostPath: /var/data/jenkins_sonar_cache mountPath: /root/.sonar/cache + workspaceVolume: + emptyDirWorkspaceVolume: + memory: false + yaml: fake disableRememberMe: true mode: EXCLUSIVE numExecutors: 0 From bceae322d757fd49bc524d236fd97671b8f29ef3 Mon Sep 17 00:00:00 2001 From: rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Wed, 3 Aug 2022 09:59:07 +0800 Subject: [PATCH 4/5] Support to replace or add a podTemplate --- pkg/k8s/cloud.go | 34 +++--- pkg/k8s/cloud_test.go | 100 +++++++++++++++++- pkg/k8s/go.mod | 17 +++ pkg/k8s/testdata/jenkins-pod-template.yaml | 26 +++++ .../k8s-podtemplate-without-annotations.yaml | 31 ++++++ pkg/k8s/testdata/result-casc.yaml | 1 - 6 files changed, 190 insertions(+), 19 deletions(-) create mode 100644 pkg/k8s/testdata/jenkins-pod-template.yaml create mode 100644 pkg/k8s/testdata/k8s-podtemplate-without-annotations.yaml diff --git a/pkg/k8s/cloud.go b/pkg/k8s/cloud.go index 2ae1ebf..aa80e4f 100644 --- a/pkg/k8s/cloud.go +++ b/pkg/k8s/cloud.go @@ -19,6 +19,14 @@ func (c *JenkinsConfig) GetConfigAsString() string { return string(c.Config) } +// ReplaceOrAddPodTemplate replace the existing PodTemplate, or add it if it's not exist +func (c *JenkinsConfig) ReplaceOrAddPodTemplate(podTemplate *v1.PodTemplate) (err error) { + if err = c.RemovePodTemplate(podTemplate.Name); err == nil { + err = c.AddPodTemplate(podTemplate) + } + return +} + // AddPodTemplate adds a PodTemplate to the Jenkins cloud config func (c *JenkinsConfig) AddPodTemplate(podTemplate *v1.PodTemplate) (err error) { casc := map[string]interface{}{} @@ -31,6 +39,7 @@ func (c *JenkinsConfig) AddPodTemplate(podTemplate *v1.PodTemplate) (err error) var ok bool if templatesObj, ok, err = unstructured.NestedField(casc, "jenkins", "clouds[0]", "kubernetes", "templates"); !ok { err = fmt.Errorf("failed to find jenkins.cloud[0]") + return } else if err != nil { return } @@ -45,12 +54,8 @@ func (c *JenkinsConfig) AddPodTemplate(podTemplate *v1.PodTemplate) (err error) templates = append(templates, targetPodTemplate) } - if err = unstructured.SetNestedField(casc, templates, "jenkins", "clouds[0]", "kubernetes", "templates"); err != nil { - return - } - - if c.Config, err = yaml.Marshal(casc); err != nil { - return + if err = unstructured.SetNestedField(casc, templates, "jenkins", "clouds[0]", "kubernetes", "templates"); err == nil { + c.Config, err = yaml.Marshal(casc) } return } @@ -119,6 +124,7 @@ func (c *JenkinsConfig) RemovePodTemplate(name string) (err error) { var ok bool if templatesObj, ok, err = unstructured.NestedField(casc, "jenkins", "clouds[0]", "kubernetes", "templates"); !ok { err = fmt.Errorf("failed to find jenkins.cloud[0]") + return } else if err != nil { return } @@ -140,12 +146,8 @@ func (c *JenkinsConfig) RemovePodTemplate(name string) (err error) { } } - if err = unstructured.SetNestedField(casc, templateArray, "jenkins", "clouds[0]", "kubernetes", "templates"); err != nil { - return - } - - if c.Config, err = yaml.Marshal(casc); err != nil { - return + if err = unstructured.SetNestedField(casc, templateArray, "jenkins", "clouds[0]", "kubernetes", "templates"); err == nil { + c.Config, err = yaml.Marshal(casc) } return } @@ -198,10 +200,10 @@ type Container struct { Args string `json:"args"` TtyEnabled bool `json:"ttyEnabled"` Privileged bool `json:"privileged"` - ResourceRequestCPU string `json:"resourceRequestCpu"` - ResourceLimitCPU string `json:"resourceLimitCpu"` - ResourceRequestMemory string `json:"resourceRequestMemory"` - ResourceLimitMemory string `json:"resourceLimitMemory"` + ResourceRequestCPU string `json:"resourceRequestCpu,omitempty"` + ResourceLimitCPU string `json:"resourceLimitCpu,omitempty"` + ResourceRequestMemory string `json:"resourceRequestMemory,omitempty"` + ResourceLimitMemory string `json:"resourceLimitMemory,omitempty"` } // WorkspaceVolume is the volume of the Jenkins agent workspace diff --git a/pkg/k8s/cloud_test.go b/pkg/k8s/cloud_test.go index b7c6ff0..0f757ee 100644 --- a/pkg/k8s/cloud_test.go +++ b/pkg/k8s/cloud_test.go @@ -1,6 +1,7 @@ package k8s import ( + "fmt" "io/ioutil" "testing" @@ -28,6 +29,16 @@ func TestJenkinsConfig_AddPodTemplate(t *testing.T) { args: args{podTemplate: readPodTemplate("testdata/k8s-podtemplate.yaml")}, expectResult: "testdata/result-casc.yaml", wantErr: false, + }, { + name: "casc is not a valid YAMl", + fields: fields{Config: []byte(`fake`)}, + args: args{podTemplate: readPodTemplate("testdata/k8s-podtemplate.yaml")}, + wantErr: true, + }, { + name: "casc has not the expect structure", + fields: fields{Config: []byte(`name: rick`)}, + args: args{podTemplate: readPodTemplate("testdata/k8s-podtemplate.yaml")}, + wantErr: true, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -38,7 +49,9 @@ func TestJenkinsConfig_AddPodTemplate(t *testing.T) { t.Errorf("AddPodTemplate() error = %v, wantErr %v", err, tt.wantErr) } - assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + if tt.expectResult != "" { + assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + } }) } } @@ -62,6 +75,16 @@ func TestJenkinsConfig_RemovePodTemplate(t *testing.T) { args: args{podTemplate: "base"}, expectResult: "testdata/casc.yaml", wantErr: false, + }, { + name: "casc is invalid", + fields: fields{Config: []byte("fake")}, + args: args{podTemplate: "base"}, + wantErr: true, + }, { + name: "casc has an unexpected structure", + fields: fields{Config: []byte(`name: rick`)}, + args: args{podTemplate: "base"}, + wantErr: true, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -71,7 +94,9 @@ func TestJenkinsConfig_RemovePodTemplate(t *testing.T) { if err := c.RemovePodTemplate(tt.args.podTemplate); (err != nil) != tt.wantErr { t.Errorf("RemovePodTemplate() error = %v, wantErr %v", err, tt.wantErr) } - assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + if tt.expectResult != "" { + assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + } }) } } @@ -84,6 +109,12 @@ func readPodTemplate(file string) (result *v1.PodTemplate) { return } +func readJenkinsPodTemplate(file string) (result JenkinsPodTemplate) { + data := readFile(file) + _ = yaml.Unmarshal(data, &result) + return +} + func readFile(file string) (data []byte) { data, _ = ioutil.ReadFile(file) return @@ -92,3 +123,68 @@ func readFile(file string) (data []byte) { func readFileASString(file string) string { return string(readFile(file)) } + +func TestJenkinsConfig_ReplaceOrAddPodTemplate(t *testing.T) { + type fields struct { + Config []byte + } + type args struct { + podTemplate *v1.PodTemplate + } + tests := []struct { + name string + fields fields + args args + expectResult string + wantErr assert.ErrorAssertionFunc + }{{ + name: "normal", + fields: fields{Config: readFile("testdata/result-casc.yaml")}, + args: args{podTemplate: readPodTemplate("testdata/k8s-podtemplate.yaml")}, + expectResult: "testdata/result-casc.yaml", + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + assert.Nil(t, err) + return true + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &JenkinsConfig{ + Config: tt.fields.Config, + } + tt.wantErr(t, c.ReplaceOrAddPodTemplate(tt.args.podTemplate), fmt.Sprintf("ReplaceOrAddPodTemplate(%v)", tt.args.podTemplate)) + assert.Equal(t, readFileASString(tt.expectResult), c.GetConfigAsString()) + }) + } +} + +func TestConvertToJenkinsPodTemplate(t *testing.T) { + type args struct { + podTemplate *v1.PodTemplate + } + tests := []struct { + name string + args args + wantTarget JenkinsPodTemplate + wantErr assert.ErrorAssertionFunc + }{{ + name: "annotation is nil", + args: args{ + podTemplate: readPodTemplate("testdata/k8s-podtemplate-without-annotations.yaml"), + }, + wantTarget: readJenkinsPodTemplate("testdata/jenkins-pod-template.yaml"), + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + assert.Nil(t, err) + return true + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTarget, err := ConvertToJenkinsPodTemplate(tt.args.podTemplate) + if !tt.wantErr(t, err, fmt.Sprintf("ConvertToJenkinsPodTemplate(%v)", tt.args.podTemplate)) { + return + } + assert.Equalf(t, tt.wantTarget, gotTarget, "ConvertToJenkinsPodTemplate(%v)", tt.args.podTemplate) + }) + } +} diff --git a/pkg/k8s/go.mod b/pkg/k8s/go.mod index 76124ba..19e61ea 100644 --- a/pkg/k8s/go.mod +++ b/pkg/k8s/go.mod @@ -8,3 +8,20 @@ require ( k8s.io/api v0.18.6 sigs.k8s.io/yaml v1.2.0 ) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gogo/protobuf v1.3.1 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/json-iterator/go v1.1.8 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect + golang.org/x/text v0.3.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect + k8s.io/apimachinery v0.18.6 // indirect + k8s.io/klog v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect +) diff --git a/pkg/k8s/testdata/jenkins-pod-template.yaml b/pkg/k8s/testdata/jenkins-pod-template.yaml new file mode 100644 index 0000000..a06a5d3 --- /dev/null +++ b/pkg/k8s/testdata/jenkins-pod-template.yaml @@ -0,0 +1,26 @@ +name: base +namespace: default +label: base +idleMinutes: 0 +containers: +- args: "" + command: cat + image: kubesphere/builder-base:v3.2.0 + name: base + privileged: false + ttyEnabled: true +nodeUsageMode: EXCLUSIVE +volumes: + - hostPathVolume: + hostPath: /var/run/docker.sock + mountPath: /var/run/docker.sock + - hostPathVolume: + hostPath: /var/data/jenkins_go_cache + mountPath: /home/jenkins/go/pkg + - hostPathVolume: + hostPath: /var/data/jenkins_sonar_cache + mountPath: /root/.sonar/cache +yaml: "" +workspaceVolume: + emptyDirWorkspaceVolume: + memory: false diff --git a/pkg/k8s/testdata/k8s-podtemplate-without-annotations.yaml b/pkg/k8s/testdata/k8s-podtemplate-without-annotations.yaml new file mode 100644 index 0000000..6656dea --- /dev/null +++ b/pkg/k8s/testdata/k8s-podtemplate-without-annotations.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: PodTemplate +metadata: + name: base + namespace: default +template: + metadata: + name: base + spec: + volumes: + - name: docker + hostPath: + path: /var/run/docker.sock + - name: gocache + hostPath: + path: /var/data/jenkins_go_cache + - name: sonarcache + hostPath: + path: /var/data/jenkins_sonar_cache + containers: + - name: base + image: kubesphere/builder-base:v3.2.0 + command: ["cat"] + args: [""] + volumeMounts: + - name: docker + mountPath: /var/run/docker.sock + - name: gocache + mountPath: /home/jenkins/go/pkg + - name: sonarcache + mountPath: /root/.sonar/cache diff --git a/pkg/k8s/testdata/result-casc.yaml b/pkg/k8s/testdata/result-casc.yaml index 49a814b..b3ae3bf 100644 --- a/pkg/k8s/testdata/result-casc.yaml +++ b/pkg/k8s/testdata/result-casc.yaml @@ -62,7 +62,6 @@ jenkins: resourceRequestCpu: 100m resourceRequestMemory: 100Mi ttyEnabled: true - volumes: null idleMinutes: 0 label: base name: base From 44b73dfef0d83cd4da89e330d6bd7f6df091d5e5 Mon Sep 17 00:00:00 2001 From: rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Wed, 3 Aug 2022 14:06:43 +0800 Subject: [PATCH 5/5] Support to set labels and inheritFrom --- pkg/k8s/cloud.go | 46 ++++++++++++++++++++------- pkg/k8s/go.mod | 2 +- pkg/k8s/go.sum | 4 +-- pkg/k8s/testdata/k8s-podtemplate.yaml | 17 +++++----- pkg/k8s/testdata/result-casc.yaml | 7 ++-- 5 files changed, 51 insertions(+), 25 deletions(-) diff --git a/pkg/k8s/cloud.go b/pkg/k8s/cloud.go index aa80e4f..910a0f6 100644 --- a/pkg/k8s/cloud.go +++ b/pkg/k8s/cloud.go @@ -73,6 +73,18 @@ func ConvertToJenkinsPodTemplate(podTemplate *v1.PodTemplate) (target JenkinsPod } annotations := podTemplate.Annotations + // set the Jenkins agent labels + if val, ok := annotations["jenkins.agent.labels"]; ok && val != "" { + labels := strings.Split(val, " ") + labels = append(labels, podTemplate.Name) + target.Label = strings.Join(labels, " ") + } + + // set the template level fields + target.YAML = annotations["containers.yaml"] + target.InheritFrom = annotations["inherit.from"] + + // convert the containers containers := podTemplate.Template.Spec.Containers containersCount := len(containers) if containersCount > 0 { @@ -80,19 +92,30 @@ func ConvertToJenkinsPodTemplate(podTemplate *v1.PodTemplate) (target JenkinsPod for i, container := range containers { name := container.Name - target.Containers[i] = Container{ - Name: name, - Image: container.Image, - Command: strings.Join(container.Command, " "), - Args: strings.Join(container.Args, " "), - ResourceLimitCPU: annotations[fmt.Sprintf("containers.%s.resourceLimitCpu", name)], - ResourceLimitMemory: annotations[fmt.Sprintf("containers.%s.resourceLimitMemory", name)], - ResourceRequestCPU: annotations[fmt.Sprintf("containers.%s.resourceRequestCpu", name)], - ResourceRequestMemory: annotations[fmt.Sprintf("containers.%s.resourceRequestMemory", name)], - TtyEnabled: true, + + jenkinsAgentContainer := Container{ + Name: name, + Image: container.Image, + Command: strings.Join(container.Command, " "), + Args: strings.Join(container.Args, " "), + TtyEnabled: true, + } + + if mem := container.Resources.Requests.Memory(); mem != nil && !mem.IsZero() { + jenkinsAgentContainer.ResourceRequestMemory = mem.String() + } + if mem := container.Resources.Limits.Memory(); mem != nil && !mem.IsZero() { + jenkinsAgentContainer.ResourceLimitMemory = mem.String() + } + if cpu := container.Resources.Requests.Cpu(); cpu != nil && !cpu.IsZero() { + jenkinsAgentContainer.ResourceRequestCPU = cpu.String() } + if cpu := container.Resources.Limits.Cpu(); cpu != nil && !cpu.IsZero() { + jenkinsAgentContainer.ResourceLimitCPU = cpu.String() + } + + target.Containers[i] = jenkinsAgentContainer } - target.YAML = annotations["containers.yaml"] container := containers[0] for _, volMount := range container.VolumeMounts { @@ -181,6 +204,7 @@ type JenkinsPodTemplate struct { NodeUsageMode string `json:"nodeUsageMode"` IdleMinutes int `json:"idleMinutes"` Containers []Container `json:"containers"` + InheritFrom string `json:"inheritFrom,omitempty"` Volumes []Volume `json:"volumes"` // YAML is the YAML format for merging into the whole PodTemplate YAML string `json:"yaml"` diff --git a/pkg/k8s/go.mod b/pkg/k8s/go.mod index 19e61ea..a5c5146 100644 --- a/pkg/k8s/go.mod +++ b/pkg/k8s/go.mod @@ -3,7 +3,7 @@ module github.com/jenkins-zh/jenkins-client/pkg/k8s go 1.18 require ( - github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb + github.com/linuxsuren/unstructured v0.0.1 github.com/stretchr/testify v1.4.0 k8s.io/api v0.18.6 sigs.k8s.io/yaml v1.2.0 diff --git a/pkg/k8s/go.sum b/pkg/k8s/go.sum index b34121c..bb179d5 100644 --- a/pkg/k8s/go.sum +++ b/pkg/k8s/go.sum @@ -41,8 +41,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb h1:ri9L96uTkrt35nOo0ktQRQ6ZT7oOy8YtAzmzf6VzX6E= -github.com/linuxsuren/unstructured v0.0.0-20220801073351-26d5b79e1feb/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as= +github.com/linuxsuren/unstructured v0.0.1 h1:ilUA8MUYbR6l9ebo/YPV2bKqlf62bzQursDSE+j00iU= +github.com/linuxsuren/unstructured v0.0.1/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= diff --git a/pkg/k8s/testdata/k8s-podtemplate.yaml b/pkg/k8s/testdata/k8s-podtemplate.yaml index 48383bb..80c511b 100644 --- a/pkg/k8s/testdata/k8s-podtemplate.yaml +++ b/pkg/k8s/testdata/k8s-podtemplate.yaml @@ -4,14 +4,8 @@ metadata: name: base namespace: default annotations: - containers.base.resourceRequestCpu: "100m" - containers.base.resourceLimitCpu: "4000m" - containers.base.resourceRequestMemory: "100Mi" - containers.base.resourceLimitMemory: "8192Mi" - containers.jnlp.resourceRequestCpu: "50m" - containers.jnlp.resourceLimitCpu: "500m" - containers.jnlp.resourceRequestMemory: "400Mi" - containers.jnlp.resourceLimitMemory: "1536Mi" + jenkins.agent.labels: "go newbase" + inherit.from: "base" containers.yaml: "fake" template: metadata: @@ -32,6 +26,13 @@ template: image: kubesphere/builder-base:v3.2.0 command: ["cat"] args: [""] + resources: + limits: + memory: 8192Mi + cpu: 4000m + requests: + memory: 100Mi + cpu: 100m volumeMounts: - name: docker mountPath: /var/run/docker.sock diff --git a/pkg/k8s/testdata/result-casc.yaml b/pkg/k8s/testdata/result-casc.yaml index b3ae3bf..0aaf800 100644 --- a/pkg/k8s/testdata/result-casc.yaml +++ b/pkg/k8s/testdata/result-casc.yaml @@ -57,13 +57,14 @@ jenkins: image: kubesphere/builder-base:v3.2.0 name: base privileged: false - resourceLimitCpu: 4000m - resourceLimitMemory: 8192Mi + resourceLimitCpu: "4" + resourceLimitMemory: 8Gi resourceRequestCpu: 100m resourceRequestMemory: 100Mi ttyEnabled: true idleMinutes: 0 - label: base + inheritFrom: base + label: go newbase base name: base namespace: default nodeUsageMode: EXCLUSIVE