File: FAQ.md

package info (click to toggle)
golang-github-gophercloud-gophercloud 0.0~git20180917.45f1c769-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 7,768 kB
  • sloc: sh: 98; makefile: 14
file content (148 lines) | stat: -rw-r--r-- 3,417 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# Tips

## Implementing default logging and re-authentication attempts

You can implement custom logging and/or limit re-auth attempts by creating a custom HTTP client
like the following and setting it as the provider client's HTTP Client (via the
`gophercloud.ProviderClient.HTTPClient` field):

```go
//...

// LogRoundTripper satisfies the http.RoundTripper interface and is used to
// customize the default Gophercloud RoundTripper to allow for logging.
type LogRoundTripper struct {
	rt                http.RoundTripper
	numReauthAttempts int
}

// newHTTPClient return a custom HTTP client that allows for logging relevant
// information before and after the HTTP request.
func newHTTPClient() http.Client {
	return http.Client{
		Transport: &LogRoundTripper{
			rt: http.DefaultTransport,
		},
	}
}

// RoundTrip performs a round-trip HTTP request and logs relevant information about it.
func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
	glog.Infof("Request URL: %s\n", request.URL)

	response, err := lrt.rt.RoundTrip(request)
	if response == nil {
		return nil, err
	}

	if response.StatusCode == http.StatusUnauthorized {
		if lrt.numReauthAttempts == 3 {
			return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
		}
		lrt.numReauthAttempts++
	}

	glog.Debugf("Response Status: %s\n", response.Status)

	return response, nil
}

endpoint := "https://127.0.0.1/auth"
pc := openstack.NewClient(endpoint)
pc.HTTPClient = newHTTPClient()

//...
```


## Implementing custom objects

OpenStack request/response objects may differ among variable names or types.

### Custom request objects

To pass custom options to a request, implement the desired `<ACTION>OptsBuilder` interface. For
example, to pass in

```go
type MyCreateServerOpts struct {
	Name string
	Size int
}
```

to `servers.Create`, simply implement the `servers.CreateOptsBuilder` interface:

```go
func (o MyCreateServeropts) ToServerCreateMap() (map[string]interface{}, error) {
	return map[string]interface{}{
		"name": o.Name,
		"size": o.Size,
	}, nil
}
```

create an instance of your custom options object, and pass it to `servers.Create`:

```go
// ...
myOpts := MyCreateServerOpts{
	Name: "s1",
	Size: "100",
}
server, err := servers.Create(computeClient, myOpts).Extract()
// ...
```

### Custom response objects

Some OpenStack services have extensions. Extensions that are supported in Gophercloud can be
combined to create a custom object:

```go
// ...
type MyVolume struct {
  volumes.Volume
  tenantattr.VolumeExt
}

var v struct {
  MyVolume `json:"volume"`
}

err := volumes.Get(client, volID).ExtractInto(&v)
// ...
```

## Overriding default `UnmarshalJSON` method

For some response objects, a field may be a custom type or may be allowed to take on
different types. In these cases, overriding the default `UnmarshalJSON` method may be
necessary. To do this, declare the JSON `struct` field tag as "-" and create an `UnmarshalJSON`
method on the type:

```go
// ...
type MyVolume struct {
	ID string `json: "id"`
	TimeCreated time.Time `json: "-"`
}

func (r *MyVolume) UnmarshalJSON(b []byte) error {
	type tmp MyVolume
	var s struct {
		tmp
		TimeCreated gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
	}
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	*r = Volume(s.tmp)

	r.TimeCreated = time.Time(s.CreatedAt)

	return err
}
// ...
```