From: Youhwan Seol Date: Thu, 1 Jun 2023 10:09:08 +0000 (+0900) Subject: Replace onboard client to ricdms client X-Git-Tag: 1.0.0~6 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=e7c18e604d502b0544558b290263927ee18a0be7;p=aiml-fw%2Faihp%2Fips%2Fkserve-adapter.git Replace onboard client to ricdms client Change-Id: Ia9926eed17e669fdf2595922de289349e28476f3 Signed-off-by: Youhwan Seol --- diff --git a/pkg/api/commons/url/url.go b/pkg/api/commons/url/url.go index a45e096..396bf35 100755 --- a/pkg/api/commons/url/url.go +++ b/pkg/api/commons/url/url.go @@ -22,9 +22,6 @@ package url // V1 returns the v1 url as a type of string. func V1() string { return "/v1" } -// Onboard returns the onboard url as a type of string. -func Onboard() string { return "/onboard/api/v1/charts" } - // IPS returns the ips url as a type of string. func IPS() string { return "/ips" } @@ -48,3 +45,9 @@ func Version() string { return "/ver" } // Preparation returns the package url as s type of string. func Preparation() string { return "/preparation" } + +// Download returns the chart download url as a type of string. +func Download() string { return "/api/v1/charts/xApp/download/{xApp_name}/ver/{version}" } + +// Onboard returns the chart Onboard url as a type of string. +func Onboard() string { return "/api/v1/custom-onboard" } diff --git a/pkg/api/v1/preparation/preparation.go b/pkg/api/v1/preparation/preparation.go index 688d2a2..1733f44 100755 --- a/pkg/api/v1/preparation/preparation.go +++ b/pkg/api/v1/preparation/preparation.go @@ -59,10 +59,11 @@ func (Executor) Preperation(c *gin.Context) { return } - chartPath, err := ipsAdapter.Preperation(configFile, schemaFile) + _, err := ipsAdapter.Preperation(configFile, schemaFile) if err != nil { utils.WriteError(c.Writer, err) return } - utils.WriteSuccess(c.Writer, http.StatusCreated, []byte(chartPath)) + + utils.WriteSuccess(c.Writer, http.StatusCreated, nil) } diff --git a/pkg/client/onboard/client.go b/pkg/client/onboard/client.go deleted file mode 100644 index 16a7d72..0000000 --- a/pkg/client/onboard/client.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -================================================================================== - -Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -================================================================================== -*/ - -package onboard - -import ( - "os" - - "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/logger" -) - -//go:generate mockgen -source=client.go -destination=./mock/mock_client.go -package=mock -type Command interface { - Get(name string) error - Download(name string, version string) (string, error) -} - -type Executor struct { - Command -} - -var ( - onboarderIP string - onboarderPort string -) - -func init() { - onboarderIP = os.Getenv("ONBOARDER_IP") - onboarderPort = os.Getenv("ONBOARDER_PORT") -} - -func (Executor) Get(name string) (err error) { - logger.Logging(logger.DEBUG, "IN") - defer logger.Logging(logger.DEBUG, "OUT") - - targetURL := buildURL(name, "") - - _, err = requestToOnboard(targetURL) - if err != nil { - return - } - return -} - -func (Executor) Download(name string, version string) (path string, err error) { - logger.Logging(logger.DEBUG, "IN") - defer logger.Logging(logger.DEBUG, "OUT") - - targetURL := buildURL(name, version) - - path, err = fetchHelmPackageFromOnboard(targetURL) - if err != nil { - return - } - return -} diff --git a/pkg/client/ricdms/client.go b/pkg/client/ricdms/client.go new file mode 100644 index 0000000..cd9ba1d --- /dev/null +++ b/pkg/client/ricdms/client.go @@ -0,0 +1,112 @@ +/* +================================================================================== + +Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +================================================================================== +*/ + +package ricdms + +import ( + "net/http" + "os" + "strconv" + + "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/errors" + "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/logger" +) + +//go:generate mockgen -source=client.go -destination=./mock/mock_client.go -package=mock +type Command interface { + OnboardHelmChart(chartPath string) error + FetchHelmChart(name string) error + FetchHelmChartAndUntar(name string, version string) (string, error) +} + +type Executor struct { + Command +} + +var ( + ricdmsIP string + ricdmsPort string +) + +func init() { + ricdmsIP = os.Getenv("RIC_DMS_IP") + ricdmsPort = os.Getenv("RIC_DMS_PORT") +} + +func (Executor) OnboardHelmChart(chartPath string) error { + logger.Logging(logger.DEBUG, "IN") + defer logger.Logging(logger.DEBUG, "OUT") + + targetURL := buildURLforChartOnboard() + + resp, err := onboardChartToRicdms(targetURL, chartPath) + if err != nil { + logger.Logging(logger.ERROR, err.Error()) + } + + if resp.StatusCode != http.StatusOK { + err = errors.InternalServerError{ + Message: "ricdms return error, status code : " + strconv.Itoa(int(resp.StatusCode)), + } + logger.Logging(logger.ERROR, err.Error()) + return err + } + return err +} + +func (Executor) FetchHelmChart(name string) (err error) { + logger.Logging(logger.DEBUG, "IN") + defer logger.Logging(logger.DEBUG, "OUT") + + targetURL, err := buildURLforChartFetch(name, "") + if err != nil { + return + } + + _, err = getChartFromRicdms(targetURL) + if err != nil { + return + } + return +} + +func (Executor) FetchHelmChartAndUntar(name string, version string) (path string, err error) { + logger.Logging(logger.DEBUG, "IN") + defer logger.Logging(logger.DEBUG, "OUT") + + targetURL, err := buildURLforChartFetch(name, version) + if err != nil { + return + } + + resp, err := getChartFromRicdms(targetURL) + if err != nil { + return + } + defer resp.Body.Close() + + path = generateRandPath(pathLength) + + err = Untar(path, resp.Body) + + if err != nil { + return + } + return +} diff --git a/pkg/client/onboard/utils.go b/pkg/client/ricdms/utils.go similarity index 70% rename from pkg/client/onboard/utils.go rename to pkg/client/ricdms/utils.go index 2a04e2e..3684b7e 100644 --- a/pkg/client/onboard/utils.go +++ b/pkg/client/ricdms/utils.go @@ -17,13 +17,15 @@ limitations under the License. ================================================================================== */ -package onboard +package ricdms import ( "archive/tar" + "bytes" "compress/gzip" "io" "math/rand" + "mime/multipart" "net/http" netUrl "net/url" "os" @@ -52,48 +54,45 @@ func init() { randSrc = rand.NewSource(time.Now().UnixNano()) } -func fetchHelmPackageFromOnboard(url string) (path string, err error) { +func buildURLforChartOnboard() string { logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") - resp, err := requestToOnboard(url) - if err != nil { - return + targetURL := netUrl.URL{ + Scheme: "http", + Host: ricdmsIP + ":" + ricdmsPort, + Path: url.Onboard(), } - defer resp.Body.Close() - - path = generateRandPath(pathLength) - err = Untar(path, resp.Body) - if err != nil { - return - } - return + return targetURL.String() } -func buildURL(name string, version string) string { +func buildURLforChartFetch(name string, version string) (string, error) { logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") targetURL := netUrl.URL{ Scheme: "http", - Host: onboarderIP + ":" + onboarderPort, - Path: url.Onboard(), + Host: ricdmsIP + ":" + ricdmsPort, + Path: url.Download(), } if name != "" { - targetURL.Path += url.IPSName() + "/" + name - - if version != "" { - targetURL.Path += url.Version() + "/" + version + targetURL.Path = strings.Replace(targetURL.Path, "{xApp_name}", name, -1) + } else { + return "", errors.InternalServerError{Message: "ifsv name is not given"} + } - } + if version != "" { + targetURL.Path = strings.Replace(targetURL.Path, "{version}", version, -1) + } else { + return "", errors.InternalServerError{Message: "ifsv version is not given"} } - return targetURL.String() + return targetURL.String(), nil } -func requestToOnboard(url string) (*http.Response, error) { +func getChartFromRicdms(url string) (*http.Response, error) { logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") @@ -105,7 +104,7 @@ func requestToOnboard(url string) (*http.Response, error) { if resp.StatusCode != http.StatusOK { err = errors.InternalServerError{ - Message: "onboard return error, status code : " + strconv.Itoa(int(resp.StatusCode)), + Message: "ricdms return error, status code : " + strconv.Itoa(int(resp.StatusCode)), } logger.Logging(logger.ERROR, err.Error()) return nil, err @@ -211,3 +210,41 @@ func generateRandPath(n int) string { return sb.String() } + +func onboardChartToRicdms(targetURL string, chartPath string) (*http.Response, error) { + logger.Logging(logger.DEBUG, "IN") + defer logger.Logging(logger.DEBUG, "OUT") + + chartFile, err := os.Open(chartPath) + if err != nil { + logger.Logging(logger.DEBUG, err.Error()) + } + defer chartFile.Close() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + fw, _ := writer.CreateFormFile("helmpkg", chartFile.Name()) + io.Copy(fw, chartFile) + writer.Close() + req, err := http.NewRequest("POST", targetURL, body) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", writer.FormDataContentType()) + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return resp, errors.InternalServerError{Message: err.Error()} + } + + if resp.StatusCode != http.StatusOK { + err = errors.InternalServerError{ + Message: "ricdms return error, status code : " + strconv.Itoa(int(resp.StatusCode)), + } + logger.Logging(logger.ERROR, err.Error()) + return resp, err + } + return resp, err +} diff --git a/pkg/controller/v1/adapter/controller.go b/pkg/controller/v1/adapter/controller.go index 0abaa4b..2af1597 100644 --- a/pkg/controller/v1/adapter/controller.go +++ b/pkg/controller/v1/adapter/controller.go @@ -23,7 +23,7 @@ import ( "os" "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/client/kserve" - "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/client/onboard" + "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/client/ricdms" "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/errors" "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/logger" "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/types" @@ -46,7 +46,7 @@ type Executor struct { } var kserveClient kserve.Command -var onboardClient onboard.Command +var ricdmsClient ricdms.Command var removeFunc func(string) error @@ -59,7 +59,7 @@ func init() { os.Exit(8) } - onboardClient = onboard.Executor{} + ricdmsClient = ricdms.Executor{} removeFunc = func(path string) (err error) { err = os.RemoveAll(path) @@ -71,7 +71,7 @@ func (Executor) Deploy(name string, version string) (revision string, err error) logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") - path, err := onboardClient.Download(name, version) + path, err := ricdmsClient.FetchHelmChartAndUntar(name, version) if err != nil { return } @@ -94,7 +94,7 @@ func (Executor) Delete(name string) (err error) { logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") - err = onboardClient.Get(name) + err = ricdmsClient.FetchHelmChart(name) if err != nil { err = errors.InvalidIPSName{ Message: err.Error(), @@ -113,7 +113,7 @@ func (Executor) Update(name string, version string, canaryTrafficRatio string) ( logger.Logging(logger.DEBUG, "IN") defer logger.Logging(logger.DEBUG, "OUT") - path, err := onboardClient.Download(name, version) + path, err := ricdmsClient.FetchHelmChartAndUntar(name, version) if err != nil { return } @@ -170,7 +170,12 @@ func (Executor) Preperation(configFile string, schemaFile string) (chartPath str chartBuilder := helm.NewChartBuilder(configFile, schemaFile) chartPath, err = chartBuilder.PackageChart() + if err != nil { + logger.Logging(logger.ERROR, err.Error()) + return + } + ricdmsClient.OnboardHelmChart(chartPath) if err != nil { return } diff --git a/pkg/controller/v1/adapter/controller_test.go b/pkg/controller/v1/adapter/controller_test.go index 7d031ee..3b916bc 100755 --- a/pkg/controller/v1/adapter/controller_test.go +++ b/pkg/controller/v1/adapter/controller_test.go @@ -27,6 +27,8 @@ import ( "github.com/kserve/kserve/pkg/apis/serving/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kservemock "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/client/kserve/mock" + ricdmsmock "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/client/ricdms/mock" "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/errors" ) @@ -62,16 +64,16 @@ func TestNegativeCalledDepolyWithInvalidYAMLPath_ExpectReturnError(t *testing.T) ctrl := gomock.NewController(t) defer ctrl.Finish() - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+invalidYAMLPath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+invalidYAMLPath, nil), ) // pass mockObj to a real object. - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -86,16 +88,16 @@ func TestNegativeCalledDepolyWithInvalidPath_ExpectReturnError(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+invalidPath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+invalidPath, nil), ) // pass mockObj to a real object. - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -111,18 +113,18 @@ func TestCalledDepoly_ExpectReturnSuccess(t *testing.T) { defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+samplePath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+samplePath, nil), kserveMockobj.EXPECT().Create(gomock.Any()), ) // pass mockObj to a real object. kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -134,14 +136,14 @@ func TestNegativeCalledDepoly_WhenOnboardClientReturnError_ExpectReturnError(t * ctrl := gomock.NewController(t) defer ctrl.Finish() - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return("", errors.InternalServerError{}), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return("", errors.InternalServerError{}), ) // pass mockObj to a real object. - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -157,18 +159,18 @@ func TestNegativeCalledDepoly_WhenKServeClientReturnError_ExpectReturnError(t *t defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+samplePath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+samplePath, nil), kserveMockobj.EXPECT().Create(gomock.Any()).Return("", errors.InternalServerError{}), ) // pass mockObj to a real object. kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -184,16 +186,16 @@ func TestCalledDelete_ExpectReturnSuccess(t *testing.T) { defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) gomock.InOrder( - onboardMockobj.EXPECT().Get(testName).Return(nil), + ricdmsmockobj.EXPECT().FetchHelmChart(testName).Return(nil), kserveMockobj.EXPECT().Delete(testName).Return(nil), ) // pass mockObj to a real object. kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -208,13 +210,13 @@ func TestNegativeCalledDelete_WhenOnboardClientReturnError_ExpectReturnError(t * ctrl := gomock.NewController(t) defer ctrl.Finish() - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) gomock.InOrder( - onboardMockobj.EXPECT().Get(testName).Return(errors.IOError{}), + ricdmsmockobj.EXPECT().FetchHelmChart(testName).Return(errors.IOError{}), ) - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -230,15 +232,15 @@ func TestNegativeCalledDelete_WhenKServeClientReturnError_ExpectReturnError(t *t defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) gomock.InOrder( - onboardMockobj.EXPECT().Get(testName).Return(nil), + ricdmsmockobj.EXPECT().FetchHelmChart(testName).Return(nil), kserveMockobj.EXPECT().Delete(testName).Return(errors.InternalServerError{}), ) kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -254,19 +256,19 @@ func TestCalledUpdate_ExpectReturnSuccess(t *testing.T) { defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+samplePath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+samplePath, nil), kserveMockobj.EXPECT().Get(testName).Return(&sampleIFSV, nil), kserveMockobj.EXPECT().Update(gomock.Any()), ) // pass mockObj to a real object. kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -278,14 +280,14 @@ func TestNegativeCalledUpdate_WhenOnboardClientReturnError_ExpectReturnError(t * ctrl := gomock.NewController(t) defer ctrl.Finish() - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return("", errors.InternalServerError{}), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return("", errors.InternalServerError{}), ) // pass mockObj to a real object. - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} @@ -301,19 +303,19 @@ func TestNegativeCalledUpdate_WhenKServeClientReturnError_ExpectReturnError(t *t defer ctrl.Finish() kserveMockobj := kservemock.NewMockCommand(ctrl) - onboardMockobj := onboardmock.NewMockCommand(ctrl) + ricdmsmockobj := ricdmsmock.NewMockCommand(ctrl) workspace, _ := os.Getwd() gomock.InOrder( - onboardMockobj.EXPECT().Download(testName, testVersion).Return(workspace+samplePath, nil), + ricdmsmockobj.EXPECT().FetchHelmChartAndUntar(testName, testVersion).Return(workspace+samplePath, nil), kserveMockobj.EXPECT().Get(testName).Return(&sampleIFSV, nil), kserveMockobj.EXPECT().Update(gomock.Any()).Return("", errors.InternalServerError{}), ) // pass mockObj to a real object. kserveClient = kserveMockobj - onboardClient = onboardMockobj + ricdmsClient = ricdmsmockobj removeFunc = fakeRemoveFunc exec := Executor{} diff --git a/pkg/helm/chart_builder.go b/pkg/helm/chart_builder.go index 0a8f522..6aa5fec 100755 --- a/pkg/helm/chart_builder.go +++ b/pkg/helm/chart_builder.go @@ -229,7 +229,7 @@ func (c *ChartBuilder) PackageChart() (chartPath string, err error) { } logger.Logging(logger.INFO, "result of helm lint : %s", string(output)) slice := strings.Split(string(output), " ") - chartPath = slice[len(slice)-1] + chartPath = strings.TrimSuffix(slice[len(slice)-1], "\n") return }