github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/FAQ.md (about) 1 # Tips 2 3 ## Implementing default logging and re-authentication attempts 4 5 You can implement custom logging and/or limit re-auth attempts by creating a custom HTTP client 6 like the following and setting it as the provider client's HTTP Client (via the 7 `golangsdk.ProviderClient.HTTPClient` field): 8 9 ```go 10 //... 11 12 // LogRoundTripper satisfies the http.RoundTripper interface and is used to 13 // customize the default Gophercloud RoundTripper to allow for logging. 14 type LogRoundTripper struct { 15 rt http.RoundTripper 16 numReauthAttempts int 17 } 18 19 // newHTTPClient return a custom HTTP client that allows for logging relevant 20 // information before and after the HTTP request. 21 func newHTTPClient() http.Client { 22 return http.Client{ 23 Transport: &LogRoundTripper{ 24 rt: http.DefaultTransport, 25 }, 26 } 27 } 28 29 // RoundTrip performs a round-trip HTTP request and logs relevant information about it. 30 func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { 31 glog.Infof("Request URL: %s\n", request.URL) 32 33 response, err := lrt.rt.RoundTrip(request) 34 if response == nil { 35 return nil, err 36 } 37 38 if response.StatusCode == http.StatusUnauthorized { 39 if lrt.numReauthAttempts == 3 { 40 return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.") 41 } 42 lrt.numReauthAttempts++ 43 } 44 45 glog.Debugf("Response Status: %s\n", response.Status) 46 47 return response, nil 48 } 49 50 endpoint := "https://127.0.0.1/auth" 51 pc := openstack.NewClient(endpoint) 52 pc.HTTPClient = newHTTPClient() 53 54 //... 55 ``` 56 57 58 ## Implementing custom objects 59 60 OpenStack request/response objects may differ among variable names or types. 61 62 ### Custom request objects 63 64 To pass custom options to a request, implement the desired `<ACTION>OptsBuilder` interface. For 65 example, to pass in 66 67 ```go 68 type MyCreateServerOpts struct { 69 Name string 70 Size int 71 } 72 ``` 73 74 to `servers.Create`, simply implement the `servers.CreateOptsBuilder` interface: 75 76 ```go 77 func (o MyCreateServeropts) ToServerCreateMap() (map[string]interface{}, error) { 78 return map[string]interface{}{ 79 "name": o.Name, 80 "size": o.Size, 81 }, nil 82 } 83 ``` 84 85 create an instance of your custom options object, and pass it to `servers.Create`: 86 87 ```go 88 // ... 89 myOpts := MyCreateServerOpts{ 90 Name: "s1", 91 Size: "100", 92 } 93 server, err := servers.Create(computeClient, myOpts).Extract() 94 // ... 95 ``` 96 97 ### Custom response objects 98 99 Some OpenStack services have extensions. Extensions that are supported in Gophercloud can be 100 combined to create a custom object: 101 102 ```go 103 // ... 104 type MyVolume struct { 105 volumes.Volume 106 tenantattr.VolumeExt 107 } 108 109 var v struct { 110 MyVolume `json:"volume"` 111 } 112 113 err := volumes.Get(client, volID).ExtractInto(&v) 114 // ... 115 ``` 116 117 ## Overriding default `UnmarshalJSON` method 118 119 For some response objects, a field may be a custom type or may be allowed to take on 120 different types. In these cases, overriding the default `UnmarshalJSON` method may be 121 necessary. To do this, declare the JSON `struct` field tag as "-" and create an `UnmarshalJSON` 122 method on the type: 123 124 ```go 125 // ... 126 type MyVolume struct { 127 ID string `json: "id"` 128 TimeCreated time.Time `json: "-"` 129 } 130 131 func (r *MyVolume) UnmarshalJSON(b []byte) error { 132 type tmp MyVolume 133 var s struct { 134 tmp 135 TimeCreated golangsdk.JSONRFC3339MilliNoZ `json:"created_at"` 136 } 137 err := json.Unmarshal(b, &s) 138 if err != nil { 139 return err 140 } 141 *r = Volume(s.tmp) 142 143 r.TimeCreated = time.Time(s.CreatedAt) 144 145 return err 146 } 147 // ... 148 ```