From fea504b0a95fec354ff470e68684a491b90c4013 Mon Sep 17 00:00:00 2001 From: Niklas Date: Mon, 7 Nov 2022 12:56:12 +0100 Subject: [PATCH 1/5] Add new method to put files with its reference. For this usecase caller of httpRequest() can bring their custom command to execute. Use this procedure to push k8s yaml via the filepath #87. --- .../ces/cesbuildlib/DoguRegistry.groovy | 3 +- .../ces/cesbuildlib/HttpClient.groovy | 39 ++++++++++++++----- .../ces/cesbuildlib/HttpClientTest.groovy | 17 ++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/com/cloudogu/ces/cesbuildlib/DoguRegistry.groovy b/src/com/cloudogu/ces/cesbuildlib/DoguRegistry.groovy index 916ffbbb..4edcb9fb 100644 --- a/src/com/cloudogu/ces/cesbuildlib/DoguRegistry.groovy +++ b/src/com/cloudogu/ces/cesbuildlib/DoguRegistry.groovy @@ -57,9 +57,8 @@ class DoguRegistry { void pushK8sYaml(String pathToYaml, String k8sName, String k8sNamespace, String versionWithoutVPrefix) { script.sh "echo 'Push Yaml:\n-Name: ${k8sName}\n-Namespace: ${k8sNamespace}\n-Version: ${versionWithoutVPrefix}'" - def k8sComponentYaml = this.sh.returnStdOut("cat ${pathToYaml}") def trimmedUrl = trimSuffix(doguRegistryURL, '/') - def result = doguRegistryHttpClient.put("${trimmedUrl}/${K8S_POST_ENDPOINT}/${k8sNamespace}/${k8sName}/${versionWithoutVPrefix}", "application/yaml", k8sComponentYaml) + def result = doguRegistryHttpClient.putFile("${trimmedUrl}/${K8S_POST_ENDPOINT}/${k8sNamespace}/${k8sName}/${versionWithoutVPrefix}", "application/yaml", pathToYaml) checkStatus(result, pathToYaml) } diff --git a/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy b/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy index c4638e9c..2e05b721 100644 --- a/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy +++ b/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy @@ -26,6 +26,11 @@ class HttpClient implements Serializable { Map put(String url, String contentType = '', def data = '') { return httpRequest('PUT', url, contentType, data) } + + Map putFile(String url, String contentType = '', String filePath) { + def command = getUploadFileCurlCommand('PUT', url, contentType, filePath) + return httpRequest('PUT', url, contentType, filePath, command) + } Map post(String url, String contentType = '', def data = '') { return httpRequest('POST', url, contentType, data) @@ -45,20 +50,36 @@ class HttpClient implements Serializable { protected String getCurlAuthParam() { "-u ${script.env.CURL_USER}:${script.env.CURL_PASSWORD}" } + + private String getCurlCommand(String httpMethod, String url, String contentType, String data) { + return "curl -i -X ${httpMethod} " + + (credentials ? "${getCurlAuthParam()} " : '') + + (contentType ? "-H 'Content-Type: ${contentType}' " : '') + + (data ? "-d '" + data + "' " : '') + + "${url}" + } + + private String getUploadFileCurlCommand(String httpMethod, String url, String contentType, String filePath) { + return "curl -i -X ${httpMethod} " + + (credentials ? "${getCurlAuthParam()} " : '') + + (contentType ? "-H 'Content-Type: ${contentType}' " : '') + + (filePath ? "-T '" + filePath + "' " : '') + + "${url}" + } - protected Map httpRequest(String httpMethod, String url, String contentType, def data) { + protected Map httpRequest(String httpMethod, String url, String contentType, def data, String customCommand = '') { String httpResponse def rawHeaders def body executeWithCredentials { - String dataStr = data.toString().replaceAll("'", "'\"'\"'") - String curlCommand = - "curl -i -X ${httpMethod} " + - (credentials ? "${getCurlAuthParam()} " : '') + - (contentType ? "-H 'Content-Type: ${contentType}' " : '') + - (data ? "-d '" + dataStr + "' " : '') + - "${url}" + String curlCommand + if (customCommand.isEmpty()) { + String dataStr = data.toString().replaceAll("'", "'\"'\"'") + curlCommand = getCurlCommand(httpMethod, url, contentType, dataStr) + } else { + curlCommand = customCommand + } // Command must be run inside this closure, otherwise the credentials will not be masked (using '*') in the console httpResponse = sh.returnStdOut curlCommand @@ -82,7 +103,7 @@ class HttpClient implements Serializable { def headers = [:] for(String line: rawHeaders) { // e.g. cache-control: no-cache - def splitLine = line.split(':', 2); + def splitLine = line.split(':', 2) headers[splitLine[0].trim()] = splitLine[1].trim() } return [ httpCode: httpCode, headers: headers, body: body] diff --git a/test/com/cloudogu/ces/cesbuildlib/HttpClientTest.groovy b/test/com/cloudogu/ces/cesbuildlib/HttpClientTest.groovy index b1c85696..d1caa5eb 100644 --- a/test/com/cloudogu/ces/cesbuildlib/HttpClientTest.groovy +++ b/test/com/cloudogu/ces/cesbuildlib/HttpClientTest.groovy @@ -46,6 +46,23 @@ class HttpClientTest { .isEqualTo('curl -i -X POST -H \'Content-Type: input\' -d \'{"title":"t","description":"d"}\' http://some-url' ) } + @Test + void "request with file upload"() { + def expectedResponse = 'HTTP/1.1 203\n' + + 'cache-control: no-cache\n' + + 'content-type: output' + scriptMock.expectedDefaultShRetValue = expectedResponse + + def actualResponse = http.putFile('http://some-url', 'input', "/path/to/file") + + assertThat(actualResponse.httpCode).isEqualTo('203') + assertThat(actualResponse.headers['content-type']).isEqualTo('output') + assertThat(actualResponse.body).isEqualTo('') + + assertThat(scriptMock.actualShMapArgs[0]) + .isEqualTo('curl -i -X PUT -H \'Content-Type: input\' -T \'/path/to/file\' http://some-url' ) + } + @Test void "response with body"() { String expectedBody1 = '{"some":"body"}\n' From 006eff969bf5517cd002bafe8b1e1215ff474fd4 Mon Sep 17 00:00:00 2001 From: Niklas Date: Mon, 7 Nov 2022 13:06:15 +0100 Subject: [PATCH 2/5] Fix unit tests #87. --- .../ces/cesbuildlib/DoguRegistryTest.groovy | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/test/com/cloudogu/ces/cesbuildlib/DoguRegistryTest.groovy b/test/com/cloudogu/ces/cesbuildlib/DoguRegistryTest.groovy index d9317bac..15236594 100644 --- a/test/com/cloudogu/ces/cesbuildlib/DoguRegistryTest.groovy +++ b/test/com/cloudogu/ces/cesbuildlib/DoguRegistryTest.groovy @@ -80,15 +80,13 @@ class DoguRegistryTest extends GroovyTestCase { void testPushYaml() { // given String yamlPath = "path.yaml" - String yaml = "apiVersion: 1" String k8sName = "dogu-operator" String namespace = "testing" String version = "1.0.0" ScriptMock scriptMock = new ScriptMock() - scriptMock.expectedShRetValueForScript.put("cat ${yamlPath}".toString(), yaml) def httpMock = mock(HttpClient.class) - when(httpMock.put('http://url.de/api/v1/k8s/testing/dogu-operator/1.0.0', 'application/yaml', yaml)).then({ invocation -> + when(httpMock.putFile('http://url.de/api/v1/k8s/testing/dogu-operator/1.0.0', 'application/yaml', yamlPath)).then({ invocation -> return [ "httpCode": '200', "body" : 'td' @@ -103,22 +101,19 @@ class DoguRegistryTest extends GroovyTestCase { // then assertEquals("echo 'Push Yaml:\n-Name: ${k8sName}\n-Namespace: ${namespace}\n-Version: ${version}'", scriptMock.allActualArgs.get(0)) - assertEquals("cat path.yaml", scriptMock.allActualArgs.get(1)) } @Test void testExitOnHttpErrorYaml() { // given String yamlPath = "path.yaml" - String yaml = "apiVersion: 1" String k8sName = "dogu-operator" String namespace = "testing" String version = "1.0.0" ScriptMock scriptMock = new ScriptMock() - scriptMock.expectedShRetValueForScript.put("cat ${yamlPath}".toString(), yaml) def httpMock = mock(HttpClient.class) - when(httpMock.put('http://url.de/api/v1/k8s/testing/dogu-operator/1.0.0', 'application/yaml', yaml)).then({ invocation -> + when(httpMock.putFile('http://url.de/api/v1/k8s/testing/dogu-operator/1.0.0', 'application/yaml', yamlPath)).then({ invocation -> return [ "httpCode": '491', "body" : 'body' @@ -133,9 +128,8 @@ class DoguRegistryTest extends GroovyTestCase { // then assertEquals("echo 'Push Yaml:\n-Name: ${k8sName}\n-Namespace: ${namespace}\n-Version: ${version}'", scriptMock.allActualArgs.get(0)) - assertEquals("cat path.yaml", scriptMock.allActualArgs.get(1)) - assertEquals("echo 'Error pushing ${yamlPath}'", scriptMock.allActualArgs.get(2)) - assertEquals("echo 'body'", scriptMock.allActualArgs.get(3)) - assertEquals("exit 1", scriptMock.allActualArgs.get(4)) + assertEquals("echo 'Error pushing ${yamlPath}'", scriptMock.allActualArgs.get(1)) + assertEquals("echo 'body'", scriptMock.allActualArgs.get(2)) + assertEquals("exit 1", scriptMock.allActualArgs.get(3)) } } From 8825c9d91adbf0f7559e476a93ccada1fb738667 Mon Sep 17 00:00:00 2001 From: Niklas Date: Mon, 7 Nov 2022 13:38:03 +0100 Subject: [PATCH 3/5] Call get upload file command in closure for credentials #87. --- CHANGELOG.md | 2 ++ src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c953dbe7..9d389512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Push k8s yaml content via file reference #87 ## [1.57.0](https://github.com/cloudogu/ces-build-lib/releases/tag/1.57.0) - 2022-10-06 ### Added diff --git a/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy b/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy index 2e05b721..bb88fb89 100644 --- a/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy +++ b/src/com/cloudogu/ces/cesbuildlib/HttpClient.groovy @@ -28,7 +28,10 @@ class HttpClient implements Serializable { } Map putFile(String url, String contentType = '', String filePath) { - def command = getUploadFileCurlCommand('PUT', url, contentType, filePath) + String command + executeWithCredentials { + command = getUploadFileCurlCommand('PUT', url, contentType, filePath) + } return httpRequest('PUT', url, contentType, filePath, command) } From 91166bed6b1c0920df8a2b3755b5a9ad1d6392a5 Mon Sep 17 00:00:00 2001 From: Robert Auer Date: Mon, 7 Nov 2022 13:43:22 +0100 Subject: [PATCH 4/5] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d389512..7390c0ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [1.58.0](https://github.com/cloudogu/ces-build-lib/releases/tag/1.58.0) - 2022-11-07 ### Changed - Push k8s yaml content via file reference #87 From aad61d2d2c75490db9d9702abd0846ee77a54026 Mon Sep 17 00:00:00 2001 From: Robert Auer Date: Mon, 7 Nov 2022 13:43:55 +0100 Subject: [PATCH 5/5] Bump version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0a3aaa7a..76ca9bf6 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.cloudogu.ces ces-build-lib ces-build-lib - 1.57.0 + 1.58.0 UTF-8