-
Notifications
You must be signed in to change notification settings - Fork 0
/
application.go
242 lines (217 loc) · 10.3 KB
/
application.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright 2022 API7.ai, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cloud
import (
"context"
"encoding/json"
"path"
"time"
)
// Application is the definition of API7 Cloud Application, which also contains
// some management fields.
type Application struct {
ApplicationSpec `json:",inline"`
// ID is the unique identify to mark an object.
ID ID `json:"id"`
// ClusterID is id of cluster that current app belong with
ClusterID ID `json:"cluster_id"`
// Status is status of app
Status EntityStatus `json:"status"`
// CreatedAt is the object creation time.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the last modified time of this object.
UpdatedAt time.Time `json:"updated_at"`
// AvailableCertIDs records the available cert ids for this app.
AvailableCertIDs []ID `json:"available_cert_ids" gorm:"-"`
// CanaryReleaseID is the canary release id that in progress
CanaryReleaseID []ID `json:"canary_release_id" gorm:"-"`
// CanaryUpstreamVersionList is the canary upstream version list that in progress or paused
CanaryUpstreamVersionList []string `json:"canary_upstream_version_list" gorm:"-"`
}
// ApplicationSpec is the specification of the Application.
type ApplicationSpec struct {
Name string `json:"name"`
Description string `json:"description"`
// Labels are used for resource classification and indexing
Labels []string `json:"labels,omitempty"`
// Protocols contains all the support protocols that this Application exposes.
Protocols []string `json:"protocols,omitempty"`
// The listening path prefix for this application
PathPrefix string `json:"path_prefix"`
// Hosts contains all the hosts that this Application uses.
Hosts []string `json:"hosts"`
// Plugins settings on Application level.
Plugins Plugins `json:"plugins,omitempty"`
// Upstream settings for the Application
Upstreams []UpstreamAndVersion `json:"upstreams"`
// DefaultUpstreamVersion settings for the upstream that should be used
DefaultUpstreamVersion string `json:"default_upstream_version,omitempty"`
// Active is status of application
// Optional values can be:
// * ActiveStatus: the object is active.
// * InactiveStatus: the object is inactive.
Active int `json:"active"`
}
// ApplicationInterface is the interface for manipulating Applications.
type ApplicationInterface interface {
// CreateApplication creates an API7 Cloud Application in the specified cluster.
// The given `app` parameter should specify the desired Application specification.
// Users need to specify the Cluster in the `opts`.
// The returned Application will contain the same Application specification plus some
// management fields and default values.
CreateApplication(ctx context.Context, app *Application, opts *ResourceCreateOptions) (*Application, error)
// UpdateApplication updates an existing API7 Cloud Application in the specified cluster.
// The given `app` parameter should specify the desired Application specification.
// Users need to specify the Cluster in the `opts`.
// The returned Application will contain the same Application specification plus some
// management fields and default values.
UpdateApplication(ctx context.Context, app *Application, opts *ResourceUpdateOptions) (*Application, error)
// DeleteApplication deletes an existing API7 Cloud Application in the specified cluster.
// The given `appID` parameter should specify the Application that you want to delete.
// Users need to specify the Cluster in the `opts`.
DeleteApplication(ctx context.Context, appID ID, opts *ResourceDeleteOptions) error
// GetApplication gets an existing API7 Cloud Application in the specified cluster.
// The given `appID` parameter should specify the Application that you want to get.
// Users need to specify the Cluster in the `opts`.
GetApplication(ctx context.Context, appID ID, opts *ResourceGetOptions) (*Application, error)
// PublishApplication publishes the Application in the specified cluster (which is
// a shortcut of UpdateApplication and set ApplicationSpec.Active to ActiveStatus).
// The given `appID` parameter should specify the Application that you want to operate.
// Users need to specify the Cluster in the `opts`.
// The updated Application will be returned and the ApplicationSpec.Active field should be ActiveStatus.
PublishApplication(ctx context.Context, appID ID, opts *ResourceUpdateOptions) (*Application, error)
// UnpublishApplication publishes the Application in the specified cluster (which is
// a shortcut of UpdateApplication and set ApplicationSpec.Active to InactiveStatus).
// The given `appID` parameter should specify the Application that you want to operate.
// Users need to specify the Cluster in the `opts`.
// The updated Application will be returned and the ApplicationSpec.Active field should be InactiveStatus.
UnpublishApplication(ctx context.Context, appID ID, opts *ResourceUpdateOptions) (*Application, error)
// ListApplications returns an iterator for listing Applications in the specified cluster with the
// given list conditions.
// Users need to specify the Cluster, Paging and Filter conditions (if necessary)
// in the `opts`.
ListApplications(ctx context.Context, opts *ResourceListOptions) (ApplicationListIterator, error)
// DebugApplicationResources returns the corresponding translated APISIX resources for this Application.
// The given `appID` parameter should specify the Application that you want to operate.
// Users need to specify the Cluster.ID in the `opts`.
DebugApplicationResources(ctx context.Context, appID ID, opts *ResourceGetOptions) (string, error)
}
// ApplicationListIterator is an iterator for listing Applications.
type ApplicationListIterator interface {
// Next returns the next Application according to the filter conditions.
Next() (*Application, error)
}
type applicationImpl struct {
client httpClient
}
type applicationListIterator struct {
iter listIterator
}
func (iter *applicationListIterator) Next() (*Application, error) {
var app Application
rawData, err := iter.iter.Next()
if err != nil {
return nil, err
}
if rawData == nil {
return nil, nil
}
if err = json.Unmarshal(rawData, &app); err != nil {
return nil, err
}
return &app, nil
}
func newApplication(cli httpClient) ApplicationInterface {
return &applicationImpl{
client: cli,
}
}
func (impl *applicationImpl) CreateApplication(ctx context.Context, app *Application, opts *ResourceCreateOptions) (*Application, error) {
var createdApp Application
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps")
err := impl.client.sendPostRequest(ctx, uri, "", app, jsonPayloadDecodeFactory(&createdApp), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return nil, err
}
return &createdApp, nil
}
func (impl *applicationImpl) UpdateApplication(ctx context.Context, app *Application, opts *ResourceUpdateOptions) (*Application, error) {
var updatedApp Application
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps", app.ID.String())
err := impl.client.sendPutRequest(ctx, uri, "", app, jsonPayloadDecodeFactory(&updatedApp), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return nil, err
}
return &updatedApp, nil
}
func (impl *applicationImpl) DeleteApplication(ctx context.Context, appID ID, opts *ResourceDeleteOptions) error {
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps", appID.String())
return impl.client.sendDeleteRequest(ctx, uri, "", nil, appendHeader(mapClusterIdFromOpts(opts)))
}
func (impl *applicationImpl) GetApplication(ctx context.Context, appID ID, opts *ResourceGetOptions) (*Application, error) {
var app Application
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps", appID.String())
err := impl.client.sendGetRequest(ctx, uri, "", jsonPayloadDecodeFactory(&app), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return nil, err
}
return &app, nil
}
func (impl *applicationImpl) PublishApplication(ctx context.Context, appID ID, opts *ResourceUpdateOptions) (*Application, error) {
var app Application
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps", appID.String())
body := []byte(`{"active":0}`)
err := impl.client.sendPatchRequest(ctx, uri, "", body, jsonPayloadDecodeFactory(&app), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return nil, err
}
return &app, nil
}
func (impl *applicationImpl) UnpublishApplication(ctx context.Context, appID ID, opts *ResourceUpdateOptions) (*Application, error) {
var app Application
clusterID := opts.Cluster.ID
uri := path.Join(_apiPathPrefix, "clusters", clusterID.String(), "apps", appID.String())
body := []byte(`{"active":1}`)
err := impl.client.sendPatchRequest(ctx, uri, "", body, jsonPayloadDecodeFactory(&app), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return nil, err
}
return &app, nil
}
func (impl *applicationImpl) ListApplications(ctx context.Context, opts *ResourceListOptions) (ApplicationListIterator, error) {
iter := listIterator{
ctx: ctx,
resource: "application",
client: impl.client,
path: path.Join(_apiPathPrefix, "clusters", opts.Cluster.ID.String(), "apps"),
paging: mergePagination(opts.Pagination),
filter: opts.Filter,
headers: appendHeader(mapClusterIdFromOpts(opts)),
}
return &applicationListIterator{iter: iter}, nil
}
func (impl *applicationImpl) DebugApplicationResources(ctx context.Context, appID ID, opts *ResourceGetOptions) (string, error) {
var rawData json.RawMessage
uri := path.Join(_apiPathPrefix, "debug", "config", "clusters", opts.Cluster.ID.String(), "application", appID.String())
err := impl.client.sendGetRequest(ctx, uri, "", jsonPayloadDecodeFactory(&rawData), appendHeader(mapClusterIdFromOpts(opts)))
if err != nil {
return "", err
}
return formatJSONData(rawData)
}