7
7
"github.com/altinity/altinity-dashboard/internal/utils"
8
8
chopv1 "github.com/altinity/clickhouse-operator/pkg/apis/clickhouse.altinity.com/v1"
9
9
"github.com/emicklei/go-restful/v3"
10
+ "github.com/kubernetes-sigs/yaml"
10
11
v1 "k8s.io/api/core/v1"
11
12
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
13
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -46,12 +47,26 @@ func (c *ChiResource) WebService(_ *WebServiceInfo) (*restful.WebService, error)
46
47
Writes ([]Chi {}).
47
48
Returns (200 , "OK" , []Chi {}))
48
49
49
- ws .Route (ws .PUT ("/{namespace}" ).To (c .handlePutCHI ).
50
- Doc ("deploy a ClickHouse Installation from YAML" ).
50
+ ws .Route (ws .GET ("/{namespace}/{name}" ).To (c .getCHIs ).
51
+ Doc ("get a single ClickHouse Installation" ).
52
+ Param (ws .PathParameter ("namespace" , "namespace to get from" ).DataType ("string" )).
53
+ Param (ws .PathParameter ("name" , "name of the CHI to get" ).DataType ("string" )).
54
+ Writes ([]Chi {}).
55
+ Returns (200 , "OK" , []Chi {}))
56
+
57
+ ws .Route (ws .POST ("/{namespace}" ).To (c .handlePostCHI ).
58
+ Doc ("deploy a new ClickHouse Installation from YAML" ).
51
59
Param (ws .PathParameter ("namespace" , "namespace to deploy to" ).DataType ("string" )).
52
60
Reads (ChiPutParams {}).
53
61
Returns (200 , "OK" , nil ))
54
62
63
+ ws .Route (ws .PATCH ("/{namespace}/{name}" ).To (c .handlePatchCHI ).
64
+ Doc ("update an existing ClickHouse Installation from YAML" ).
65
+ Param (ws .PathParameter ("namespace" , "namespace the CHI is in" ).DataType ("string" )).
66
+ Param (ws .PathParameter ("name" , "name of the CHI to update" ).DataType ("string" )).
67
+ Reads (ChiPutParams {}).
68
+ Returns (200 , "OK" , nil ))
69
+
55
70
ws .Route (ws .DELETE ("/{namespace}/{name}" ).To (c .handleDeleteCHI ).
56
71
Doc ("delete a ClickHouse installation" ).
57
72
Param (ws .PathParameter ("namespace" , "namespace to delete from" ).DataType ("string" )).
@@ -66,10 +81,20 @@ func (c *ChiResource) getCHIs(request *restful.Request, response *restful.Respon
66
81
if ! ok {
67
82
namespace = ""
68
83
}
84
+ name , ok := request .PathParameters ()["name" ]
85
+ if ! ok {
86
+ name = ""
87
+ }
69
88
70
89
k := utils .GetK8s ()
90
+ var fieldSelector string
91
+ if name != "" {
92
+ fieldSelector = "metadata.name=" + name
93
+ }
71
94
chis , err := k .ChopClientset .ClickhouseV1 ().ClickHouseInstallations (namespace ).List (
72
- context .TODO (), metav1.ListOptions {})
95
+ context .TODO (), metav1.ListOptions {
96
+ FieldSelector : fieldSelector ,
97
+ })
73
98
if err != nil {
74
99
webError (response , http .StatusBadRequest , "listing CHIs" , err )
75
100
return
@@ -85,7 +110,8 @@ func (c *ChiResource) getCHIs(request *restful.Request, response *restful.Respon
85
110
},
86
111
MatchExpressions : nil ,
87
112
}
88
- pods , err := getK8sPodsFromLabelSelector (chi .Namespace , sel )
113
+ var pods * v1.PodList
114
+ pods , err = getK8sPodsFromLabelSelector (chi .Namespace , sel )
89
115
if err == nil {
90
116
for _ , pod := range getPodsFromK8sPods (pods ) {
91
117
chClusterPod := CHClusterPod {
@@ -130,65 +156,107 @@ func (c *ChiResource) getCHIs(request *restful.Request, response *restful.Respon
130
156
}
131
157
}
132
158
}
159
+ var y []byte
160
+ y , err = yaml .Marshal (ResourceSpec {
161
+ APIVersion : chi .APIVersion ,
162
+ Kind : chi .Kind ,
163
+ Metadata : ResourceSpecMetadata {
164
+ Name : chi .Name ,
165
+ Namespace : chi .Namespace ,
166
+ ResourceVersion : chi .ResourceVersion ,
167
+ },
168
+ Spec : chi .Spec ,
169
+ })
170
+ if err != nil {
171
+ y = nil
172
+ }
133
173
list = append (list , Chi {
134
174
Name : chi .Name ,
135
175
Namespace : chi .Namespace ,
136
176
Status : chi .Status .Status ,
137
177
Clusters : chi .Status .ClustersCount ,
138
178
Hosts : chi .Status .HostsCount ,
139
179
ExternalURL : externalURL ,
180
+ ResourceYAML : string (y ),
140
181
CHClusterPods : chClusterPods ,
141
182
})
142
183
}
143
184
_ = response .WriteEntity (list )
144
185
}
145
186
146
187
var ErrNamespaceRequired = errors .New ("namespace is required" )
147
- var ErrNameAndNamespaceRequired = errors .New ("name and namespace are required" )
188
+ var ErrNameRequired = errors .New ("name is required" )
148
189
var ErrYAMLMustBeCHI = errors .New ("YAML document must contain a single ClickhouseInstallation definition" )
149
190
150
- func (c * ChiResource ) handlePutCHI (request * restful.Request , response * restful.Response ) {
191
+ func (c * ChiResource ) handlePostOrPatchCHI (request * restful.Request , response * restful.Response , doPost bool ) {
151
192
namespace , ok := request .PathParameters ()["namespace" ]
152
193
if ! ok || namespace == "" {
153
194
webError (response , http .StatusBadRequest , "processing request" , ErrNamespaceRequired )
154
195
return
155
196
}
197
+ name := ""
198
+ if ! doPost {
199
+ name , ok = request .PathParameters ()["name" ]
200
+ if ! ok || name == "" {
201
+ webError (response , http .StatusBadRequest , "processing request" , ErrNameRequired )
202
+ return
203
+ }
204
+ }
156
205
157
206
putParams := ChiPutParams {}
158
207
err := request .ReadEntity (& putParams )
159
208
if err != nil {
160
209
webError (response , http .StatusBadRequest , "reading request body" , err )
161
210
return
162
211
}
163
- var rejected = false
164
- err = utils .GetK8s ().DoApplySelectively (putParams .YAML , namespace ,
165
- func (candidates []* unstructured.Unstructured ) []* unstructured.Unstructured {
166
- if len (candidates ) != 1 {
167
- rejected = true
168
- return nil
169
- }
170
- if candidates [0 ].GetKind () != "ClickHouseInstallation" {
171
- rejected = true
172
- return nil
173
- }
174
- return candidates
175
- })
176
- if rejected {
212
+
213
+ k := utils .GetK8s ()
214
+ var obj * unstructured.Unstructured
215
+ obj , err = k .DecodeYAMLToObject (putParams .YAML )
216
+ if err != nil {
217
+ webError (response , http .StatusBadRequest , "parsing YAML object" , err )
218
+ return
219
+ }
220
+ if obj .GetAPIVersion () != "clickhouse.altinity.com/v1" ||
221
+ obj .GetKind () != "ClickHouseInstallation" ||
222
+ (! doPost && (obj .GetNamespace () != namespace ||
223
+ obj .GetName () != name )) {
177
224
webError (response , http .StatusBadRequest , "processing request" , ErrYAMLMustBeCHI )
178
225
return
179
226
}
227
+ var errSource string
228
+ if doPost {
229
+ errSource = "creating CHI"
230
+ err = k .SingleObjectCreate (obj , namespace )
231
+ } else {
232
+ errSource = "updating CHI"
233
+ err = k .SingleObjectUpdate (obj , namespace )
234
+ }
180
235
if err != nil {
181
- webError (response , http .StatusInternalServerError , "applying CHI" , err )
236
+ webError (response , http .StatusInternalServerError , errSource , err )
182
237
return
183
238
}
184
239
_ = response .WriteEntity (nil )
185
240
}
186
241
242
+ func (c * ChiResource ) handlePostCHI (request * restful.Request , response * restful.Response ) {
243
+ c .handlePostOrPatchCHI (request , response , true )
244
+ }
245
+
246
+ func (c * ChiResource ) handlePatchCHI (request * restful.Request , response * restful.Response ) {
247
+ c .handlePostOrPatchCHI (request , response , false )
248
+ }
249
+
187
250
func (c * ChiResource ) handleDeleteCHI (request * restful.Request , response * restful.Response ) {
188
- namespace , ok1 := request .PathParameters ()["namespace" ]
189
- name , ok2 := request .PathParameters ()["name" ]
190
- if ! ok1 || ! ok2 || name == "" || namespace == "" {
191
- webError (response , http .StatusBadRequest , "processing request" , ErrNameAndNamespaceRequired )
251
+ namespace , ok := request .PathParameters ()["namespace" ]
252
+ if ! ok || namespace == "" {
253
+ webError (response , http .StatusBadRequest , "processing request" , ErrNamespaceRequired )
254
+ return
255
+ }
256
+ var name string
257
+ name , ok = request .PathParameters ()["name" ]
258
+ if ! ok || name == "" {
259
+ webError (response , http .StatusBadRequest , "processing request" , ErrNameRequired )
192
260
return
193
261
}
194
262
0 commit comments