Skip to content

Commit 8088428

Browse files
committed
feat(debug) support response tracing
* add support for `DEBUG=3` to trace raw HTTP responses * fix scenario, when `HTML5_CACHE=1` is used for the first time and configuration file not yet exists * fix pagination issue, convert absolute URLs of the next page to relative, when calling `cf curl` internally * update README.md with SSL configuration documentation * update CHANGELOG.md * bump version to 1.4.9
1 parent 5de3813 commit 8088428

39 files changed

+304
-130
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88

9+
## [1.4.8] - 2024-02-19
10+
### Added
11+
- Support `DEBUG=3` to print raw responses in the trace logs
12+
13+
### Fixed
14+
- Wait until the CF job of service key or service instrance deletion is completed
15+
- Create new configuration file on first call of CLI with `HTML5_CACHE=1` flag
16+
- Handle CloudFoundry `v3` API pagination with absolute next URL
17+
918
## [1.4.8] - 2024-01-18
1019
### Added
1120
- Respect `cf` CLI TLS settings, including `--skip-ssl-validation` login option as well as `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables ([#65](https://github.com/SAP/cf-html5-apps-repo-cli-plugin/issues/65))

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
NAME=cf-html5-apps-repo-cli-plugin
2-
VERSION=1.4.8
2+
VERSION=1.4.9
33

44
# Build the project
55
all: clean build install

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ The configuration of the CF HTML5 Applications Repository CLI Plugin is done by
281281
The following are supported:
282282
* `DEBUG=1` - enables trace logs with detailed information about currently running steps. If you want to
283283
see also the sensitive information in the trace logs (e.g. access tokens), use `DEBUG=2` instead.
284+
To see the raw HTTP responses in trace logs, use `DEBUG=3`.
284285
* `HTML5_CACHE=1` - enables persisted cache. Disabled by default. Should be enabled only for sequential
285286
execution of the CF HTML5 Applications Repository CLI Plugin commands in the same context
286287
(org/space/user) during short period of time (less than 12 hours)
@@ -297,6 +298,7 @@ In addition CF HTML5 Applications Repository CLI Plugin supports the following c
297298
* `--skip-ssl-validation` - command line argument option of `cf login`
298299
* `SSL_CERT_FILE` - environment variable pointing to file with additional signing certificate
299300
* `SSL_CERT_DIR` - environment variable pointing to directory with `server.crt` file containing additional signing certificate
301+
As an alternative, you can (install)[https://docs.cloudfoundry.org/cf-cli/self-signed.html] custom or self-signed certificate on machine, where CLI is running.
300302
301303
## Troubleshooting
302304
@@ -310,6 +312,15 @@ these service instances. If one of the flows invoked by the CF HTML5 Application
310312
Repository CLI Plugin fails in the middle, these artifacts may remain
311313
in the current space.
312314
315+
#### Self-signed Certificates
316+
317+
Note, that on macOS Cloud Foundry CLI itself (does not support)[https://github.com/cloudfoundry/cli/issues/1263] the `SSL_CERT_FILE` and `SSL_CERT_DIR`.
318+
Therefore, running the CLI commands is only possible if at least one of two conditions is met:
319+
* The login was done with `cf login --skip-ssl-validation`, and all subsequent CLI commands ignore certificate issues
320+
* The certificate of Cloud Foundry deployment was installed on machine, where CLI is running
321+
322+
Trying to use both `--skip-ssl-validation` and `SSL_CERT_FILE` will result in commands, targeting Cloud Foundry Cloud Controller, executed without certificate validation, and commands targeting services (e.g. HTML5 Applications Repository) will check server certificate using `SSL_CERT_FILE`.
323+
313324
## Limitations
314325
315326
Currently, you can't use the CF HTML5 Applications Repository CLI Plugin with

clients/create_service_instance.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"cf-html5-apps-repo-cli-plugin/log"
77
"encoding/json"
88
"fmt"
9-
"io/ioutil"
9+
"io"
1010
"net/http"
1111
"strconv"
1212
"time"
@@ -73,12 +73,14 @@ func CreateServiceInstance(cliConnection plugin.CliConnection, spaceGUID string,
7373
}
7474
defer response.Body.Close()
7575

76+
body, err = io.ReadAll(response.Body)
77+
log.Trace(log.Response{Head: response, Body: body})
78+
if err != nil {
79+
return nil, err
80+
}
81+
7682
if response.StatusCode != 202 {
77-
body, err = ioutil.ReadAll(response.Body)
78-
if err != nil {
79-
return nil, err
80-
}
81-
return nil, fmt.Errorf("Could not create service instance: [%d] %s", response.StatusCode, string(body))
83+
return nil, fmt.Errorf("Could not create service instance: [%d] %s", response.StatusCode, string(body[:]))
8284
}
8385

8486
// Pool job

clients/create_service_instance_destination.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ func CreateServiceInstanceDestination(serviceURL string, accessToken string, des
4444
}
4545
defer response.Body.Close()
4646

47+
body, err = io.ReadAll(response.Body)
48+
log.Trace(log.Response{Head: response, Body: body})
49+
if err != nil {
50+
return err
51+
}
52+
4753
if response.StatusCode > 201 {
48-
body, err = io.ReadAll(response.Body)
49-
if err != nil {
50-
return fmt.Errorf("Could not create destination: [%s] %+v", response.Status, body)
51-
}
54+
return fmt.Errorf("Could not create destination: [%s] %+v", response.Status, body)
5255
}
5356

5457
return nil

clients/create_service_key.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"cf-html5-apps-repo-cli-plugin/log"
77
"encoding/json"
88
"fmt"
9-
"io/ioutil"
9+
"io"
1010
"net/http"
1111
"strconv"
1212
"time"
@@ -69,11 +69,13 @@ func CreateServiceKey(cliConnection plugin.CliConnection, serviceInstanceGUID st
6969
}
7070
defer response.Body.Close()
7171

72+
body, err = io.ReadAll(response.Body)
73+
log.Trace(log.Response{Head: response, Body: body})
74+
if err != nil {
75+
return nil, err
76+
}
77+
7278
if response.StatusCode != 202 {
73-
body, err = ioutil.ReadAll(response.Body)
74-
if err != nil {
75-
return nil, err
76-
}
7779
return nil, fmt.Errorf("Could not create service key: [%d] %s", response.StatusCode, string(body))
7880
}
7981

clients/create_subaccount_destination.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
models "cf-html5-apps-repo-cli-plugin/clients/models"
66
"cf-html5-apps-repo-cli-plugin/log"
77
"fmt"
8-
"io/ioutil"
8+
"io"
99
"net/http"
1010
)
1111

@@ -44,8 +44,14 @@ func CreateSubaccountDestination(serviceURL string, accessToken string, destinat
4444
}
4545
defer response.Body.Close()
4646

47+
body, err = io.ReadAll(response.Body)
48+
log.Trace(log.Response{Head: response, Body: body})
49+
if err != nil {
50+
return err
51+
}
52+
4753
if response.StatusCode > 201 {
48-
body, err = ioutil.ReadAll(response.Body)
54+
body, err = io.ReadAll(response.Body)
4955
if err != nil {
5056
return fmt.Errorf("Could not create destination: [%s] %+v", response.Status, body)
5157
}

clients/delete_service_content.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package clients
33
import (
44
"cf-html5-apps-repo-cli-plugin/log"
55
"errors"
6+
"io"
67
"net/http"
78
)
89

@@ -28,6 +29,9 @@ func DeleteServiceContent(serviceURL string, accessToken string) error {
2829
if response, err = client.Do(request); err != nil {
2930
return err
3031
}
32+
defer response.Body.Close()
33+
body, err := io.ReadAll(response.Body)
34+
log.Trace(log.Response{Head: response, Body: body})
3135
if response.StatusCode != 200 {
3236
return errors.New(response.Status)
3337
}

clients/delete_service_instance.go

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package clients
22

33
import (
4-
models "cf-html5-apps-repo-cli-plugin/clients/models"
4+
"bytes"
55
"cf-html5-apps-repo-cli-plugin/log"
6-
"encoding/json"
7-
"errors"
8-
"strings"
6+
"fmt"
7+
"io"
8+
"net/http"
99

1010
"github.com/cloudfoundry/cli/plugin"
1111
)
@@ -14,43 +14,59 @@ import (
1414
func DeleteServiceInstance(cliConnection plugin.CliConnection, serviceInstanceGUID string, maxRetryCount int) error {
1515
var err error
1616
var url string
17-
var responseStrings []string
18-
var responseBytes []byte
19-
var errorResponse models.CFErrorResponse
2017
var currentTry = 1
18+
var request *http.Request
19+
var response *http.Response
20+
var body []byte
21+
var apiEndpoint string
22+
var accessToken string
2123

22-
url = "/v3/service_instances/" + serviceInstanceGUID
24+
apiEndpoint, err = cliConnection.ApiEndpoint()
25+
if err != nil {
26+
return err
27+
}
28+
29+
accessToken, err = cliConnection.AccessToken()
30+
if err != nil {
31+
return err
32+
}
33+
34+
url = apiEndpoint + "/v3/service_instances/" + serviceInstanceGUID
2335

2436
for currentTry <= maxRetryCount {
25-
log.Tracef("Making request to (try %d/%d): %s\n", currentTry, maxRetryCount, url)
26-
responseStrings, err = cliConnection.CliCommandWithoutTerminalOutput("curl", url, "-X", "DELETE")
37+
log.Tracef("Making request to: %s (try %d/%d)\n", url, currentTry, maxRetryCount)
38+
request, err = http.NewRequest("DELETE", url, bytes.NewBuffer([]byte{}))
2739
if err != nil {
2840
return err
2941
}
42+
request.Header.Set("Content-Type", "application/json")
43+
request.Header.Set("Authorization", accessToken)
3044

31-
responseBytes = []byte(strings.Join(responseStrings, ""))
32-
if len(responseBytes) > 0 {
33-
log.Tracef("Response is not empty, maybe error: %+v\n", responseStrings)
34-
errorResponse = models.CFErrorResponse{}
35-
err = json.Unmarshal(responseBytes, &errorResponse)
36-
if err != nil {
37-
return err
38-
}
39-
if len(errorResponse) == 0 {
40-
return errors.New(strings.Join(responseStrings, "\n"))
41-
}
42-
if errorResponse[0].Code > 0 {
43-
if currentTry == maxRetryCount {
44-
if errorResponse[0].Title != "" || errorResponse[0].Detail != "" {
45-
return errors.New(errorResponse[0].Title + " " + errorResponse[0].Detail)
46-
}
47-
return errors.New(strings.Join(responseStrings, "\n"))
48-
}
49-
currentTry++
45+
client, err := GetDefaultClient()
46+
if err != nil {
47+
return err
48+
}
49+
response, err = client.Do(request)
50+
if err != nil {
51+
return err
52+
}
53+
defer response.Body.Close()
54+
55+
body, err = io.ReadAll(response.Body)
56+
log.Trace(log.Response{Head: response, Body: body})
57+
if err != nil {
58+
return err
59+
}
60+
61+
if response.StatusCode != 202 {
62+
if currentTry != maxRetryCount {
5063
continue
5164
}
65+
return fmt.Errorf("Could not delete service instance: [%d] %s", response.StatusCode, string(body[:]))
5266
} else {
53-
return nil
67+
// Pool job
68+
_, err = PollJob(cliConnection, response.Header.Get("Location"))
69+
return err
5470
}
5571
}
5672

clients/delete_service_instance_destination.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func DeleteServiceInstanceDestination(serviceURL string, accessToken string, des
3535
return err
3636
}
3737
defer response.Body.Close()
38-
38+
log.Trace(log.Response{Head: response})
3939
if response.StatusCode > 201 {
4040
body, err = io.ReadAll(response.Body)
4141
if err != nil {

0 commit comments

Comments
 (0)