-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcloudrun.go
137 lines (109 loc) · 3.36 KB
/
cloudrun.go
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
package run
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"time"
)
var cloudrunEndpoint = "https://%s-run.googleapis.com"
// ErrNameResolutionPermissionDenied is returned when access to the
// Cloud Run API is denied.
var ErrNameResolutionPermissionDenied = errors.New("run: permission denied to named service")
// ErrNameResolutionUnauthorized is returned when calls to the Cloud
// Run API are unauthorized.
var ErrNameResolutionUnauthorized = errors.New("run: cloud run api unauthorized")
// ErrServiceNotFound is returned when a service is not found.
var ErrServiceNotFound = errors.New("run: named service not found")
// ErrNameResolutionUnknownError is return when calls to the Cloud Run
// API return an unknown error.
var ErrNameResolutionUnknownError = errors.New("run: unexpected error retrieving named service")
// ErrNameResolutionUnexpectedResponse is returned when calls to the Cloud Run
// API return an unexpected response.
type ErrNameResolutionUnexpectedResponse struct {
StatusCode int
Err error
}
func (e *ErrNameResolutionUnexpectedResponse) Error() string {
return "run: unexpected error retrieving named service"
}
func (e *ErrNameResolutionUnexpectedResponse) Unwrap() error { return e.Err }
// Service represents a Cloud Run service.
type Service struct {
Status ServiceStatus `json:"status"`
}
// ServiceStatus holds the current state of the Cloud Run service.
type ServiceStatus struct {
// URL holds the url that will distribute traffic over the
// provided traffic targets. It generally has the form
// https://{route-hash}-{project-hash}-{cluster-level-suffix}.a.run.app
URL string `json:"url"`
// Similar to url, information on where the service is available on HTTP.
Address ServiceAddress `json:"address"`
}
type ServiceAddress struct {
URL string `json:"url"`
}
func regionalEndpoint(region string) string {
if region == "test" {
return cloudrunEndpoint
}
return fmt.Sprintf(cloudrunEndpoint, region)
}
func getService(name, region, project string) (*Service, error) {
var err error
if region == "" {
region, err = Region()
if err != nil {
return nil, err
}
}
if project == "" {
project, err = ProjectID()
if err != nil {
return nil, err
}
}
endpoint := fmt.Sprintf("%s/apis/serving.knative.dev/v1/namespaces/%s/services/%s",
regionalEndpoint(region), project, name)
token, err := Token([]string{"https://www.googleapis.com/auth/cloud-platform"})
if err != nil {
return nil, err
}
request, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
return nil, err
}
request.Header.Set("User-Agent", userAgent)
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token.AccessToken))
timeout := time.Duration(5) * time.Second
httpClient := &http.Client{Timeout: timeout}
response, err := httpClient.Do(request)
if err != nil {
return nil, err
}
defer response.Body.Close()
switch s := response.StatusCode; s {
case 200:
break
case 401:
return nil, ErrNameResolutionUnauthorized
case 403:
return nil, ErrNameResolutionPermissionDenied
case 404:
return nil, ErrServiceNotFound
default:
return nil, &ErrNameResolutionUnexpectedResponse{s, ErrNameResolutionUnknownError}
}
var service Service
data, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(data, &service)
if err != nil {
return nil, err
}
return &service, nil
}