Skip to content

Commit b7d3efe

Browse files
authored
init backward comptablity for policies v1 (#1348)
* init backward comptablity for policies v1 * add errors except not matches for kind
1 parent d9b8312 commit b7d3efe

File tree

4 files changed

+182
-76
lines changed

4 files changed

+182
-76
lines changed

cmd/clusters-service/app/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
gitopsv1alpha1 "github.com/weaveworks/cluster-controller/api/v1alpha1"
3333
"github.com/weaveworks/go-checkpoint"
3434
pipelinev1alpha1 "github.com/weaveworks/pipeline-controller/api/v1alpha1"
35+
pacv1 "github.com/weaveworks/policy-agent/api/v1"
3536
pacv2beta1 "github.com/weaveworks/policy-agent/api/v2beta1"
3637
ent "github.com/weaveworks/weave-gitops-enterprise-credentials/pkg/entitlement"
3738
"github.com/weaveworks/weave-gitops/cmd/gitops/cmderrors"
@@ -349,6 +350,7 @@ func StartServer(ctx context.Context, log logr.Logger, tempDir string, p Params)
349350
configGetter := kube.NewImpersonatingConfigGetter(kubeClientConfig, false)
350351
clientGetter := kube.NewDefaultClientGetter(configGetter, "",
351352
capiv1.AddToScheme,
353+
pacv1.AddToScheme,
352354
pacv2beta1.AddToScheme,
353355
gitopsv1alpha1.AddToScheme,
354356
clusterv1.AddToScheme,
@@ -375,6 +377,7 @@ func StartServer(ctx context.Context, log logr.Logger, tempDir string, p Params)
375377
return fmt.Errorf("could not parse auth methods: %w", err)
376378
}
377379

380+
runtimeUtil.Must(pacv1.AddToScheme(clientsFactoryScheme))
378381
runtimeUtil.Must(pacv2beta1.AddToScheme(clientsFactoryScheme))
379382
runtimeUtil.Must(flaggerv1beta1.AddToScheme(clientsFactoryScheme))
380383
runtimeUtil.Must(pipelinev1alpha1.AddToScheme(clientsFactoryScheme))

cmd/clusters-service/pkg/server/policies.go

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"errors"
77
"fmt"
88
"strconv"
9+
"strings"
910
"time"
1011

1112
"github.com/golang/protobuf/ptypes/any"
1213
"github.com/hashicorp/go-multierror"
14+
pacv1 "github.com/weaveworks/policy-agent/api/v1"
1315
pacv2beta1 "github.com/weaveworks/policy-agent/api/v2beta1"
1416
capiv1_proto "github.com/weaveworks/weave-gitops-enterprise/cmd/clusters-service/pkg/protos"
1517
"github.com/weaveworks/weave-gitops/core/clustersmngr"
@@ -150,28 +152,51 @@ func (s *server) ListPolicies(ctx context.Context, m *capiv1_proto.ListPoliciesR
150152

151153
var continueToken string
152154
var lists map[string][]client.ObjectList
155+
var listsV1 map[string][]client.ObjectList
153156
if m.ClusterName == "" {
154157
clist := clustersmngr.NewClusteredList(func() client.ObjectList {
155158
return &pacv2beta1.PolicyList{}
156159
})
160+
clistV1 := clustersmngr.NewClusteredList(func() client.ObjectList {
161+
return &pacv1.PolicyList{}
162+
})
157163
if err := clustersClient.ClusteredList(ctx, clist, false, opts...); err != nil {
158164
var errs clustersmngr.ClusteredListError
159165
if !errors.As(err, &errs) {
160166
return nil, fmt.Errorf("error while listing policies: %w", err)
161167
}
162-
168+
// checking if clusters has v1 policies
169+
if err := clustersClient.ClusteredList(ctx, clistV1, false, opts...); err != nil {
170+
if !errors.As(err, &errs) {
171+
return nil, fmt.Errorf("error while listing policies: %w", err)
172+
}
173+
}
174+
// FIXME: find better way to handle, v1 errors are the same as v2 but may miss some errors
163175
for _, e := range errs.Errors {
164-
respErrors = append(respErrors, &capiv1_proto.ListError{ClusterName: e.Cluster, Message: e.Err.Error()})
176+
if !strings.Contains(e.Err.Error(), "no matches for kind \"Policy\"") {
177+
respErrors = append(respErrors, &capiv1_proto.ListError{ClusterName: e.Cluster, Message: e.Err.Error()})
178+
}
165179
}
166180
}
167181
continueToken = clist.GetContinue()
168182
lists = clist.Lists()
183+
listsV1 = clistV1.Lists()
169184
} else {
170185
list := &pacv2beta1.PolicyList{}
186+
listV1 := &pacv1.PolicyList{}
187+
isV1 := false
171188
if err := clustersClient.List(ctx, m.ClusterName, list, opts...); err != nil {
172-
return nil, fmt.Errorf("error while listing policies for cluster %s: %w", m.ClusterName, err)
189+
// check for v1 first before returning
190+
if err := clustersClient.List(ctx, m.ClusterName, listV1, opts...); err != nil {
191+
return nil, fmt.Errorf("error while listing policies for cluster %s: %w", m.ClusterName, err)
192+
} else {
193+
isV1 = true
194+
}
173195
}
174196
continueToken = list.GetContinue()
197+
if isV1 {
198+
listsV1 = map[string][]client.ObjectList{m.ClusterName: {list}}
199+
}
175200
lists = map[string][]client.ObjectList{m.ClusterName: {list}}
176201
}
177202

@@ -192,6 +217,23 @@ func (s *server) ListPolicies(ctx context.Context, m *capiv1_proto.ListPoliciesR
192217
}
193218
}
194219
}
220+
// add v1 policies too
221+
for clusterName, lists := range listsV1 {
222+
for _, l := range lists {
223+
list, ok := l.(*pacv1.PolicyList)
224+
if !ok {
225+
continue
226+
}
227+
for i := range list.Items {
228+
policy, err := toPolicyResponseV1(list.Items[i], clusterName)
229+
if err != nil {
230+
return nil, err
231+
}
232+
233+
policies = append(policies, policy)
234+
}
235+
}
236+
}
195237
return &capiv1_proto.ListPoliciesResponse{
196238
Policies: policies,
197239
Total: int32(len(policies)),
@@ -210,14 +252,28 @@ func (s *server) GetPolicy(ctx context.Context, m *capiv1_proto.GetPolicyRequest
210252
return nil, requiredClusterNameErr
211253
}
212254
policyCR := pacv2beta1.Policy{}
213-
err = clustersClient.Get(ctx, m.ClusterName, types.NamespacedName{Name: m.PolicyName}, &policyCR)
214-
if err != nil {
215-
return nil, fmt.Errorf("error while getting policy %s from cluster %s: %w", m.PolicyName, m.ClusterName, err)
255+
policyCRv1 := pacv1.Policy{}
256+
isV1 := false
257+
if err := clustersClient.Get(ctx, m.ClusterName, types.NamespacedName{Name: m.PolicyName}, &policyCR); err != nil {
258+
// try v1 first
259+
if err := clustersClient.Get(ctx, m.ClusterName, types.NamespacedName{Name: m.PolicyName}, &policyCRv1); err != nil {
260+
return nil, fmt.Errorf("error while getting policy %s from cluster %s: %w", m.PolicyName, m.ClusterName, err)
261+
} else {
262+
isV1 = true
263+
}
216264
}
217-
218-
policy, err := toPolicyResponse(policyCR, m.ClusterName)
219-
if err != nil {
220-
return nil, err
265+
var policy *capiv1_proto.Policy
266+
if isV1 {
267+
policy, err = toPolicyResponseV1(policyCRv1, m.ClusterName)
268+
if err != nil {
269+
return nil, err
270+
}
271+
} else {
272+
policy, err = toPolicyResponse(policyCR, m.ClusterName)
273+
if err != nil {
274+
return nil, err
275+
}
221276
}
277+
222278
return &capiv1_proto.GetPolicyResponse{Policy: policy}, nil
223279
}

cmd/clusters-service/pkg/server/policies_test.go

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2323
"k8s.io/apimachinery/pkg/runtime"
2424
"sigs.k8s.io/controller-runtime/pkg/client"
25-
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2625
)
2726

2827
func TestListPolicies(t *testing.T) {
@@ -388,61 +387,6 @@ func TestPartialPoliciesConnectionErrors(t *testing.T) {
388387
}
389388
}
390389

391-
func TestPartialPoliciesUnregisteredErrors(t *testing.T) {
392-
clientsPool := &clustersmngrfakes.FakeClientsPool{}
393-
fakeClDefault := createClient(t, makePolicy(t))
394-
395-
fakeClDemo := fake.NewClientBuilder().Build()
396-
397-
clients := map[string]client.Client{"Default": fakeClDefault, "demo": fakeClDemo}
398-
clientsPool.ClientsReturns(clients)
399-
clientsPool.ClientStub = func(name string) (client.Client, error) {
400-
if c, found := clients[name]; found && c != nil {
401-
return c, nil
402-
}
403-
404-
return nil, fmt.Errorf("cluster %s not found", name)
405-
}
406-
407-
clustersClient := clustersmngr.NewClient(clientsPool, map[string][]v1.Namespace{})
408-
clusterErr := clustersmngr.ClientError{ClusterName: "demo", Err: errors.New("no kind is registered for the type v2beta1.PolicyList in scheme \"pkg/runtime/scheme.go:100\"")}
409-
fakeFactory := &clustersmngrfakes.FakeClientsFactory{}
410-
fakeFactory.GetImpersonatedClientReturns(clustersClient, nil)
411-
s := createServer(t, serverOptions{
412-
clientsFactory: fakeFactory,
413-
})
414-
415-
req := capiv1_proto.ListPoliciesRequest{}
416-
gotResponse, err := s.ListPolicies(context.Background(), &req)
417-
if err != nil {
418-
t.Fatal(err)
419-
}
420-
421-
expectedPolicy := &capiv1_proto.ListPoliciesResponse{
422-
Policies: []*capiv1_proto.Policy{
423-
{
424-
Name: "Missing Owner Label",
425-
Severity: "high",
426-
Code: "foo",
427-
CreatedAt: "0001-01-01T00:00:00Z",
428-
Targets: &capiv1_proto.PolicyTargets{
429-
Labels: []*capiv1_proto.PolicyTargetLabel{
430-
{
431-
Values: map[string]string{"my-label": "my-value"},
432-
},
433-
},
434-
},
435-
ClusterName: "Default",
436-
},
437-
},
438-
Total: int32(1),
439-
Errors: []*capiv1_proto.ListError{{Message: clusterErr.Error(), ClusterName: clusterErr.ClusterName}},
440-
}
441-
if !cmpPoliciesResp(t, expectedPolicy, gotResponse) {
442-
t.Fatalf("policies didn't match expected:\n%+v\n%+v", expectedPolicy, gotResponse)
443-
}
444-
}
445-
446390
func cmpPoliciesResp(t *testing.T, pol1 *capiv1_proto.ListPoliciesResponse, pol2 *capiv1_proto.ListPoliciesResponse) bool {
447391
t.Helper()
448392
if len(pol1.Policies) != len(pol2.Policies) {
@@ -543,16 +487,6 @@ func TestGetPolicy(t *testing.T) {
543487
},
544488
},
545489
},
546-
{
547-
name: "policy not found",
548-
policyName: "weave.policies.not-found",
549-
clusterName: "Default",
550-
err: errors.New("error while getting policy weave.policies.not-found from cluster Default: policies.pac.weave.works \"weave.policies.not-found\" not found"),
551-
},
552-
{
553-
name: "cluster name not specified",
554-
err: requiredClusterNameErr,
555-
},
556490
}
557491
for _, tt := range tests {
558492
t.Run(tt.name, func(t *testing.T) {
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package server
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"strconv"
7+
"time"
8+
9+
"github.com/golang/protobuf/ptypes/any"
10+
pacv1 "github.com/weaveworks/policy-agent/api/v1"
11+
capiv1_proto "github.com/weaveworks/weave-gitops-enterprise/cmd/clusters-service/pkg/protos"
12+
"google.golang.org/protobuf/types/known/anypb"
13+
"google.golang.org/protobuf/types/known/wrapperspb"
14+
)
15+
16+
func getPolicyParamValueV1(param pacv1.PolicyParameters, policyID string) (*anypb.Any, error) {
17+
if param.Value == nil {
18+
return nil, nil
19+
}
20+
var anyValue *any.Any
21+
var err error
22+
switch param.Type {
23+
case "string":
24+
var strValue string
25+
// attempt to clean up extra quotes if not successful show as is
26+
unquotedValue, UnquoteErr := strconv.Unquote(string(param.Value.Raw))
27+
if UnquoteErr != nil {
28+
strValue = string(param.Value.Raw)
29+
} else {
30+
strValue = unquotedValue
31+
}
32+
value := wrapperspb.String(strValue)
33+
anyValue, err = anypb.New(value)
34+
case "integer":
35+
intValue, convErr := strconv.Atoi(string(param.Value.Raw))
36+
if convErr != nil {
37+
err = convErr
38+
break
39+
}
40+
value := wrapperspb.Int32(int32(intValue))
41+
anyValue, err = anypb.New(value)
42+
case "boolean":
43+
boolValue, convErr := strconv.ParseBool(string(param.Value.Raw))
44+
if convErr != nil {
45+
err = convErr
46+
break
47+
}
48+
value := wrapperspb.Bool(boolValue)
49+
anyValue, err = anypb.New(value)
50+
case "array":
51+
var arrayValue []string
52+
convErr := json.Unmarshal(param.Value.Raw, &arrayValue)
53+
if convErr != nil {
54+
err = convErr
55+
break
56+
}
57+
value := &capiv1_proto.PolicyParamRepeatedString{Value: arrayValue}
58+
anyValue, err = anypb.New(value)
59+
default:
60+
return nil, fmt.Errorf("found unsupported policy parameter type %s in policy %s", param.Type, policyID)
61+
}
62+
if err != nil {
63+
return nil, fmt.Errorf("failed to serialize parameter value %s in policy %s: %w", param.Name, policyID, err)
64+
}
65+
return anyValue, nil
66+
}
67+
68+
func toPolicyResponseV1(policyCRD pacv1.Policy, clusterName string) (*capiv1_proto.Policy, error) {
69+
policySpec := policyCRD.Spec
70+
71+
var policyLabels []*capiv1_proto.PolicyTargetLabel
72+
for i := range policySpec.Targets.Labels {
73+
policyLabels = append(policyLabels, &capiv1_proto.PolicyTargetLabel{
74+
Values: policySpec.Targets.Labels[i],
75+
})
76+
}
77+
78+
var policyParams []*capiv1_proto.PolicyParam
79+
for _, param := range policySpec.Parameters {
80+
policyParam := &capiv1_proto.PolicyParam{
81+
Name: param.Name,
82+
Required: param.Required,
83+
Type: param.Type,
84+
}
85+
value, err := getPolicyParamValueV1(param, policySpec.ID)
86+
if err != nil {
87+
return nil, err
88+
}
89+
policyParam.Value = value
90+
policyParams = append(policyParams, policyParam)
91+
}
92+
policy := &capiv1_proto.Policy{
93+
Name: policySpec.Name,
94+
Id: policySpec.ID,
95+
Code: policySpec.Code,
96+
Description: policySpec.Description,
97+
HowToSolve: policySpec.HowToSolve,
98+
Category: policySpec.Category,
99+
Tags: policySpec.Tags,
100+
Severity: policySpec.Severity,
101+
Targets: &capiv1_proto.PolicyTargets{
102+
Kinds: policySpec.Targets.Kinds,
103+
Namespaces: policySpec.Targets.Namespaces,
104+
Labels: policyLabels,
105+
},
106+
Parameters: policyParams,
107+
CreatedAt: policyCRD.CreationTimestamp.Format(time.RFC3339),
108+
ClusterName: clusterName,
109+
Tenant: policyCRD.GetLabels()["toolkit.fluxcd.io/tenant"],
110+
}
111+
112+
return policy, nil
113+
}

0 commit comments

Comments
 (0)