@@ -17,12 +17,14 @@ package sdk
17
17
import (
18
18
"context"
19
19
"encoding/json"
20
- "fmt "
20
+ "time "
21
21
22
+ "go.uber.org/zap"
22
23
"google.golang.org/grpc"
23
24
"google.golang.org/grpc/codes"
24
25
"google.golang.org/grpc/status"
25
26
27
+ "github.com/pipe-cd/pipecd/pkg/model"
26
28
"github.com/pipe-cd/pipecd/pkg/plugin/api/v1alpha1/livestate"
27
29
)
28
30
31
33
Plugin
32
34
33
35
Register (server * grpc.Server )
34
- setCommonFields (commonFields )
35
- setConfig ([]byte ) error
36
+ setFields (commonFields ) error
36
37
livestate.LivestateServiceServer
37
38
}
38
39
)
@@ -46,7 +47,7 @@ type LivestatePlugin[Config, DeployTargetConfig any] interface {
46
47
// GetLivestate returns the live state of the resources in the given application.
47
48
// It returns the resources' live state and the difference between the desired state and the live state.
48
49
// It's allowed to return only the resources' live state if the difference is not available, or only the difference if the live state is not available.
49
- GetLivestate (context.Context , * Config , []* DeployTarget [DeployTargetConfig ], TODO ) (TODO , error )
50
+ GetLivestate (context.Context , * Config , []* DeployTarget [DeployTargetConfig ], * GetLivestateInput ) (* GetLivestateResponse , error )
50
51
}
51
52
52
53
// LivestatePluginServer is a wrapper for LivestatePlugin to satisfy the LivestateServiceServer interface.
@@ -55,8 +56,9 @@ type LivestatePluginServer[Config, DeployTargetConfig any] struct {
55
56
livestate.UnimplementedLivestateServiceServer
56
57
commonFields
57
58
58
- base LivestatePlugin [Config , DeployTargetConfig ]
59
- config Config
59
+ base LivestatePlugin [Config , DeployTargetConfig ]
60
+ config Config
61
+ deployTargets map [string ]* DeployTarget [DeployTargetConfig ]
60
62
}
61
63
62
64
// RegisterLivestatePlugin registers the given LivestatePlugin to the sdk.
@@ -79,23 +81,257 @@ func (s *LivestatePluginServer[Config, DeployTargetConfig]) Register(server *grp
79
81
livestate .RegisterLivestateServiceServer (server , s )
80
82
}
81
83
82
- // setCommonFields sets the common fields to the plugin server.
83
- func (s * LivestatePluginServer [Config , DeployTargetConfig ]) setCommonFields (c commonFields ) {
84
- s .commonFields = c
85
- }
84
+ // setFields sets the common fields and configs to the server.
85
+ func (s * LivestatePluginServer [Config , DeployTargetConfig ]) setFields (fields commonFields ) error {
86
+ s .commonFields = fields
86
87
87
- // setConfig sets the configuration to the plugin server.
88
- func (s * LivestatePluginServer [Config , DeployTargetConfig ]) setConfig (bytes []byte ) error {
89
- if bytes == nil {
90
- return nil
88
+ cfg := fields .config
89
+ if cfg .Config != nil {
90
+ if err := json .Unmarshal (cfg .Config , & s .config ); err != nil {
91
+ s .logger .Fatal ("failed to unmarshal the plugin config" , zap .Error (err ))
92
+ return err
93
+ }
91
94
}
92
- if err := json .Unmarshal (bytes , & s .config ); err != nil {
93
- return fmt .Errorf ("failed to unmarshal config: %w" , err )
95
+
96
+ s .deployTargets = make (map [string ]* DeployTarget [DeployTargetConfig ], len (cfg .DeployTargets ))
97
+ for _ , dt := range cfg .DeployTargets {
98
+ var sdkDt DeployTargetConfig
99
+ if err := json .Unmarshal (dt .Config , & sdkDt ); err != nil {
100
+ s .logger .Fatal ("failed to unmarshal deploy target config" , zap .Error (err ))
101
+ return err
102
+ }
103
+ s .deployTargets [dt .Name ] = & DeployTarget [DeployTargetConfig ]{
104
+ Name : dt .Name ,
105
+ Labels : dt .Labels ,
106
+ Config : sdkDt ,
107
+ }
94
108
}
109
+
95
110
return nil
96
111
}
97
112
98
113
// GetLivestate returns the live state of the resources in the given application.
99
- func (s * LivestatePluginServer [Config , DeployTargetConfig ]) GetLivestate (context.Context , * livestate.GetLivestateRequest ) (* livestate.GetLivestateResponse , error ) {
100
- return nil , status .Errorf (codes .Unimplemented , "method GetLivestate not implemented" )
114
+ func (s * LivestatePluginServer [Config , DeployTargetConfig ]) GetLivestate (ctx context.Context , request * livestate.GetLivestateRequest ) (* livestate.GetLivestateResponse , error ) {
115
+ // Get the deploy targets set on the deployment from the piped plugin config.
116
+ deployTargets := make ([]* DeployTarget [DeployTargetConfig ], 0 , len (request .GetDeployTargets ()))
117
+ for _ , name := range request .GetDeployTargets () {
118
+ dt , ok := s .deployTargets [name ]
119
+ if ! ok {
120
+ return nil , status .Errorf (codes .Internal , "the deploy target %s is not found in the piped plugin config" , name )
121
+ }
122
+
123
+ deployTargets = append (deployTargets , dt )
124
+ }
125
+
126
+ client := & Client {
127
+ base : s .client ,
128
+ pluginName : s .Name (),
129
+ applicationID : request .GetApplicationId (),
130
+ toolRegistry : s .toolRegistry ,
131
+ }
132
+
133
+ response , err := s .base .GetLivestate (ctx , & s .config , deployTargets , & GetLivestateInput {
134
+ Request : GetLivestateRequest {
135
+ ApplicationID : request .ApplicationId ,
136
+ DeploymentSource : newDeploymentSource (request .GetDeploySource ()),
137
+ },
138
+ Client : client ,
139
+ Logger : s .logger ,
140
+ })
141
+ if err != nil {
142
+ return nil , status .Errorf (codes .Internal , "failed to get the live state: %v" , err )
143
+ }
144
+
145
+ return response .toModel (time .Now ()), nil
146
+ }
147
+
148
+ // GetLivestateInput is the input for the GetLivestate method.
149
+ type GetLivestateInput struct {
150
+ // Request is the request for getting the live state.
151
+ Request GetLivestateRequest
152
+ // Client is the client for accessing the piped API.
153
+ Client * Client
154
+ // Logger is the logger for logging.
155
+ Logger * zap.Logger
156
+ }
157
+
158
+ // GetLivestateRequest is the request for the GetLivestate method.
159
+ type GetLivestateRequest struct {
160
+ // ApplicationID is the ID of the application.
161
+ ApplicationID string
162
+ // DeploymentSource is the source of the deployment.
163
+ DeploymentSource DeploymentSource
164
+ }
165
+
166
+ // GetLivestateResponse is the response for the GetLivestate method.
167
+ type GetLivestateResponse struct {
168
+ // LiveState is the live state of the application.
169
+ LiveState ApplicationLiveState
170
+ // SyncState is the sync state of the application.
171
+ SyncState ApplicationSyncState
172
+ }
173
+
174
+ // toModel converts the GetLivestateResponse to the model.GetLivestateResponse.
175
+ func (r * GetLivestateResponse ) toModel (now time.Time ) * livestate.GetLivestateResponse {
176
+ return & livestate.GetLivestateResponse {
177
+ ApplicationLiveState : r .LiveState .toModel (now ),
178
+ SyncState : r .SyncState .toModel (now ),
179
+ }
180
+ }
181
+
182
+ // ApplicationLiveState represents the live state of an application.
183
+ type ApplicationLiveState struct {
184
+ Resources []ResourceState
185
+ HealthStatus ApplicationHealthStatus
186
+ }
187
+
188
+ // toModel converts the ApplicationLiveState to the model.ApplicationLiveState.
189
+ func (s * ApplicationLiveState ) toModel (now time.Time ) * model.ApplicationLiveState {
190
+ resources := make ([]* model.ResourceState , 0 , len (s .Resources ))
191
+ for _ , rs := range s .Resources {
192
+ resources = append (resources , rs .toModel (now ))
193
+ }
194
+ return & model.ApplicationLiveState {
195
+ Resources : resources ,
196
+ HealthStatus : s .HealthStatus .toModel (),
197
+ }
198
+ }
199
+
200
+ // ResourceState represents the live state of a resource.
201
+ type ResourceState struct {
202
+ // ID is the unique identifier of the resource.
203
+ ID string
204
+ // ParentIDs is the list of the parent resource's IDs.
205
+ ParentIDs []string
206
+ // Name is the name of the resource.
207
+ Name string
208
+ // ResourceType is the type of the resource.
209
+ ResourceType string
210
+ // ResourceMetadata is the metadata of the resource.
211
+ ResourceMetadata map [string ]string
212
+ // HealthStatus is the health status of the resource.
213
+ HealthStatus ResourceHealthStatus
214
+ // HealthDescription is the description of the health status.
215
+ HealthDescription string
216
+ // DeployTarget is the target where the resource is deployed.
217
+ DeployTarget string
218
+ // PluginName is the name of the plugin that provides the resource.
219
+ PluginName string
220
+ // CreatedAt is the time when the resource was created.
221
+ CreatedAt time.Time
222
+ }
223
+
224
+ // toModel converts the ResourceState to the model.ResourceState.
225
+ func (s * ResourceState ) toModel (now time.Time ) * model.ResourceState {
226
+ return & model.ResourceState {
227
+ Id : s .ID ,
228
+ ParentIds : s .ParentIDs ,
229
+ Name : s .Name ,
230
+ ResourceType : s .ResourceType ,
231
+ ResourceMetadata : s .ResourceMetadata ,
232
+ HealthStatus : s .HealthStatus .toModel (),
233
+ HealthDescription : s .HealthDescription ,
234
+ DeployTarget : s .DeployTarget ,
235
+ PluginName : s .PluginName ,
236
+ CreatedAt : s .CreatedAt .Unix (),
237
+ UpdatedAt : now .Unix (),
238
+ }
239
+ }
240
+
241
+ // ApplicationHealthStatus represents the health status of an application.
242
+ type ApplicationHealthStatus int
243
+
244
+ const (
245
+ // ApplicationHealthStateUnknown represents the unknown health status of an application.
246
+ ApplicationHealthStateUnknown ApplicationHealthStatus = iota
247
+ // ApplicationHealthStateHealthy represents the healthy health status of an application.
248
+ ApplicationHealthStateHealthy
249
+ // ApplicationHealthStateOther represents the other health status of an application.
250
+ ApplicationHealthStateOther
251
+ )
252
+
253
+ // toModel converts the ApplicationHealthStatus to the model.ApplicationLiveState_Status.
254
+ func (s ApplicationHealthStatus ) toModel () model.ApplicationLiveState_Status {
255
+ switch s {
256
+ case ApplicationHealthStateHealthy :
257
+ return model .ApplicationLiveState_HEALTHY
258
+ case ApplicationHealthStateOther :
259
+ return model .ApplicationLiveState_OTHER
260
+ default :
261
+ return model .ApplicationLiveState_UNKNOWN
262
+ }
263
+ }
264
+
265
+ // ResourceHealthStatus represents the health status of a resource.
266
+ type ResourceHealthStatus int
267
+
268
+ const (
269
+ // ResourceHealthStateUnknown represents the unknown health status of a resource.
270
+ ResourceHealthStateUnknown ResourceHealthStatus = iota
271
+ // ResourceHealthStateHealthy represents the healthy health status of a resource.
272
+ ResourceHealthStateHealthy
273
+ // ResourceHealthStateUnhealthy represents the unhealthy health status of a resource.
274
+ ResourceHealthStateUnhealthy
275
+ )
276
+
277
+ // toModel converts the ResourceHealthStatus to the model.ResourceState_HealthStatus.
278
+ func (s ResourceHealthStatus ) toModel () model.ResourceState_HealthStatus {
279
+ switch s {
280
+ case ResourceHealthStateHealthy :
281
+ return model .ResourceState_HEALTHY
282
+ case ResourceHealthStateUnhealthy :
283
+ return model .ResourceState_UNHEALTHY
284
+ default :
285
+ return model .ResourceState_UNKNOWN
286
+ }
287
+ }
288
+
289
+ // ApplicationSyncState represents the sync state of an application.
290
+ type ApplicationSyncState struct {
291
+ // Status is the sync status of the application.
292
+ Status ApplicationSyncStatus
293
+ // ShortReason is the short reason of the sync status.
294
+ // for example, "The service manifest doesn't be synced"
295
+ ShortReason string
296
+ // Reason is the reason of the sync status.
297
+ // actually, it's the difference between the desired state and the live state.
298
+ Reason string
299
+ }
300
+
301
+ // toModel converts the ApplicationSyncState to the model.ApplicationSyncState.
302
+ func (s * ApplicationSyncState ) toModel (now time.Time ) * model.ApplicationSyncState {
303
+ return & model.ApplicationSyncState {
304
+ Status : s .Status .toModel (),
305
+ ShortReason : s .ShortReason ,
306
+ Reason : s .Reason ,
307
+ Timestamp : now .Unix (),
308
+ }
309
+ }
310
+
311
+ // ApplicationSyncStatus represents the sync status of an application.
312
+ type ApplicationSyncStatus int
313
+
314
+ const (
315
+ // ApplicationSyncStateUnknown represents the unknown sync status of an application.
316
+ ApplicationSyncStateUnknown ApplicationSyncStatus = iota
317
+ // ApplicationSyncStateSynced represents the synced sync status of an application.
318
+ ApplicationSyncStateSynced
319
+ // ApplicationSyncStateOutOfSync represents the out-of-sync sync status of an application.
320
+ ApplicationSyncStateOutOfSync
321
+ // ApplicationSyncStateInvalidConfig represents the invalid-config sync status of an application.
322
+ ApplicationSyncStateInvalidConfig
323
+ )
324
+
325
+ // toModel converts the ApplicationSyncStatus to the model.ApplicationSyncStatus.
326
+ func (s ApplicationSyncStatus ) toModel () model.ApplicationSyncStatus {
327
+ switch s {
328
+ case ApplicationSyncStateSynced :
329
+ return model .ApplicationSyncStatus_SYNCED
330
+ case ApplicationSyncStateOutOfSync :
331
+ return model .ApplicationSyncStatus_OUT_OF_SYNC
332
+ case ApplicationSyncStateInvalidConfig :
333
+ return model .ApplicationSyncStatus_INVALID_CONFIG
334
+ default :
335
+ return model .ApplicationSyncStatus_UNKNOWN
336
+ }
101
337
}
0 commit comments