@@ -18,13 +18,15 @@ import (
18
18
"cmp"
19
19
"context"
20
20
"fmt"
21
+ "strings"
21
22
22
23
"go.uber.org/zap"
23
24
24
25
kubeconfig "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes/config"
25
26
"github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes/provider"
26
27
"github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes/toolregistry"
27
28
config "github.com/pipe-cd/pipecd/pkg/configv1"
29
+ "github.com/pipe-cd/pipecd/pkg/plugin/diff"
28
30
"github.com/pipe-cd/pipecd/pkg/plugin/sdk"
29
31
)
30
32
@@ -75,15 +77,78 @@ func (p Plugin) GetLivestate(ctx context.Context, _ sdk.ConfigNone, deployTarget
75
77
resourceStates = append (resourceStates , m .ToResourceState (deployTarget .Name ))
76
78
}
77
79
80
+ manifests , err := p .loadManifests (ctx , input , cfg .Spec , provider .NewLoader (toolRegistry ))
81
+ if err != nil {
82
+ input .Logger .Error ("Failed to load manifests" , zap .Error (err ))
83
+ return nil , err
84
+ }
85
+
86
+ liveManifests := make ([]provider.Manifest , 0 , len (namespacedLiveResources )+ len (clusterScopedLiveResources ))
87
+ liveManifests = append (liveManifests , namespacedLiveResources ... )
88
+ liveManifests = append (liveManifests , clusterScopedLiveResources ... )
89
+
90
+ // Calculate SyncState by comparing live manifests with desired manifests
91
+ // TODO: Implement drift detection ignore configs
92
+ diffResult , err := provider .DiffList (liveManifests , manifests , input .Logger ,
93
+ diff .WithEquateEmpty (),
94
+ diff .WithIgnoreAddingMapKeys (),
95
+ diff .WithCompareNumberAndNumericString (),
96
+ )
97
+ if err != nil {
98
+ input .Logger .Error ("Failed to calculate diff" , zap .Error (err ))
99
+ return nil , err
100
+ }
101
+
102
+ syncState := calculateSyncState (diffResult , input .Request .DeploymentSource .CommitHash )
103
+
78
104
return & sdk.GetLivestateResponse {
79
105
LiveState : sdk.ApplicationLiveState {
80
106
Resources : resourceStates ,
81
107
HealthStatus : sdk .ApplicationHealthStateUnknown , // TODO: Implement health status calculation
82
108
},
83
- SyncState : sdk. ApplicationSyncState {}, // TODO: Implement sync state calculation
109
+ SyncState : syncState ,
84
110
}, nil
85
111
}
86
112
113
+ func calculateSyncState (diffResult * provider.DiffListResult , commit string ) sdk.ApplicationSyncState {
114
+ if diffResult .NoChanges () {
115
+ return sdk.ApplicationSyncState {
116
+ Status : sdk .ApplicationSyncStateSynced ,
117
+ ShortReason : "" ,
118
+ Reason : "" ,
119
+ }
120
+ }
121
+
122
+ total := len (diffResult .Adds ) + len (diffResult .Deletes ) + len (diffResult .Changes )
123
+ shortReason := fmt .Sprintf ("There are %d manifests not synced (%d adds, %d deletes, %d changes)" ,
124
+ total ,
125
+ len (diffResult .Adds ),
126
+ len (diffResult .Deletes ),
127
+ len (diffResult .Changes ),
128
+ )
129
+
130
+ if len (commit ) > 7 {
131
+ commit = commit [:7 ]
132
+ }
133
+
134
+ var b strings.Builder
135
+ b .WriteString (fmt .Sprintf ("Diff between the defined state in Git at commit %s and actual state in cluster:\n \n " , commit ))
136
+ b .WriteString ("--- Actual (LiveState)\n +++ Expected (Git)\n \n " )
137
+
138
+ details := diffResult .Render (provider.DiffRenderOptions {
139
+ MaskSecret : true ,
140
+ MaskConfigMap : true ,
141
+ MaxChangedManifests : 3 ,
142
+ })
143
+ b .WriteString (details )
144
+
145
+ return sdk.ApplicationSyncState {
146
+ Status : sdk .ApplicationSyncStateOutOfSync ,
147
+ ShortReason : shortReason ,
148
+ Reason : b .String (),
149
+ }
150
+ }
151
+
87
152
// Name implements sdk.LivestatePlugin.
88
153
func (p Plugin ) Name () string {
89
154
return "kubernetes" // TODO: make this constant to share with deployment plugin
@@ -93,3 +158,31 @@ func (p Plugin) Name() string {
93
158
func (p Plugin ) Version () string {
94
159
return "0.0.1" // TODO: make this constant to share with deployment plugin
95
160
}
161
+
162
+ type loader interface {
163
+ // LoadManifests renders and loads all manifests for application.
164
+ LoadManifests (ctx context.Context , input provider.LoaderInput ) ([]provider.Manifest , error )
165
+ }
166
+
167
+ // TODO: share this implementation with the deployment plugin
168
+ func (p Plugin ) loadManifests (ctx context.Context , input * sdk.GetLivestateInput , spec * kubeconfig.KubernetesApplicationSpec , loader loader ) ([]provider.Manifest , error ) {
169
+ manifests , err := loader .LoadManifests (ctx , provider.LoaderInput {
170
+ PipedID : input .Request .PipedID ,
171
+ AppID : input .Request .ApplicationID ,
172
+ CommitHash : input .Request .DeploymentSource .CommitHash ,
173
+ AppName : input .Request .ApplicationName ,
174
+ AppDir : input .Request .DeploymentSource .ApplicationDirectory ,
175
+ ConfigFilename : input .Request .DeploymentSource .ApplicationConfigFilename ,
176
+ Manifests : spec .Input .Manifests ,
177
+ Namespace : spec .Input .Namespace ,
178
+ TemplatingMethod : provider .TemplatingMethodNone , // TODO: Implement detection of templating method or add it to the config spec.
179
+
180
+ // TODO: Define other fields for LoaderInput
181
+ })
182
+
183
+ if err != nil {
184
+ return nil , err
185
+ }
186
+
187
+ return manifests , nil
188
+ }
0 commit comments