-
Notifications
You must be signed in to change notification settings - Fork 16
Implement SaaS-Based Approval Workflow for ClientIntents #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
omris94
wants to merge
56
commits into
main
Choose a base branch
from
evya/approved_intents_crd
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
5b7b610
Adding approved intents types
evyatarmeged c42bca3
Adding approved client intents crd & changes to existing client intents
evyatarmeged 110130c
Adding approval flow for OSS (auto approve) and a reconciler for appr…
evyatarmeged 5b8e437
tweaks to main with revamped intents reconciler
evyatarmeged 52e917c
Merge branch 'main' of https://github.com/otterize/intents-operator i…
evyatarmeged f59a2e2
Adding cloud approval flow and some genqlient tweaks
evyatarmeged 95cd18c
Changing everything to approved client intents model
evyatarmeged c2a1ba6
Adding periodic approval flow
evyatarmeged d8593fd
Adding polling for approval updates
evyatarmeged 9def051
demo commit
evyatarmeged 02855f6
latest fixes
evyatarmeged 269cd19
fixes
evyatarmeged e226fcb
function updates
evyatarmeged ee676e9
Making resource UID the hash for intents approval reporting
evyatarmeged 089beb1
Copying old status fields from client intents to approved client intents
evyatarmeged 9be3ee7
Added old status update to approved client intents
evyatarmeged 2ce015c
Refactor client intents handling to use approved intents and update G…
sapirwo 607771d
Move to v2beta1, write webhooks
omris94 89267a0
Merge remote-tracking branch 'origin/main' into evya/approved_intents…
omris94 2f79886
fixup
omris94 5854619
Align with the Cloud API
omris94 5adf83e
Make tests work
omris94 edd567b
uncomment
omris94 6b1fa5b
Fix CRDs
omris94 f40a859
Add delete and update logic
omris94 8772e86
Merge remote-tracking branch 'origin/main' into evya/approved_intents…
omris94 77d6a51
Do it idempotent
omris94 be9e44e
Fix updates
omris94 f16a610
Add tests improve upToDate logic
omris94 66e4adc
Remove deprecation
omris94 26e0d5c
Merge remote-tracking branch 'origin/main' into evya/approved_intents…
omris94 04d771a
bugfix isShared
omris94 3831311
helm
omris94 e2d0592
update makefile
omris94 75eac3d
order
omris94 937bc85
reorder
omris94 aa0a712
remove use of upToDate; add events
omris94 d2e2689
Mirror events from approvedClientIntents to ClientIntents
omris94 98ace92
Add events for status review changes
omris94 f9a94d6
Add upToDateReconcilers who watches ApprovedClientIntents aligns thei…
omris94 fe0fe76
Approved client intents migration - The webhook will create approvedC…
omris94 8ac6005
Use finalizer with clientIntents -
omris94 15e40eb
Add config for cloud approval
omris94 4d8c424
Use the same name for intents and approved intents
omris94 da7a996
Align with cloud API
omris94 6d8ab8e
Merge remote-tracking branch 'origin/main' into evya/approved_intents…
omris94 f94286c
fixup makefile
omris94 b2347fc
generate
omris94 74a7dbd
fixup
omris94 599debe
fixup
omris94 ffb98a6
lint fix
omris94 0f7ad84
Update helm
omris94 d571172
Merge remote-tracking branch 'origin/main' into evya/approved_intents…
omris94 07f990c
Add resolved IPs to the migration
omris94 d7a6a32
fix events strings
omris94 21fcd63
remove not in use
omris94 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Submodule helm-charts
updated
12 files
+1 −1 | .github/workflows/bump-version.yaml | |
+1 −1 | README.md | |
+2 −2 | credentials-operator/Chart.yaml | |
+2 −2 | intents-operator/Chart.yaml | |
+26 −0 | intents-operator/templates/intents-operator-manager-clusterrole.yaml | |
+0 −2 | intents-operator/values.yaml | |
+2 −2 | network-mapper/Chart.yaml | |
+16 −4 | network-mapper/templates/agent-daemonset.yaml | |
+4 −2 | network-mapper/values.yaml | |
+1 −1 | otterize-kubernetes/Chart.yaml | |
+11 −11 | tests/go.mod | |
+26 −24 | tests/go.sum |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
235 changes: 235 additions & 0 deletions
235
src/operator/api/v2alpha1/approved_clientintents_types.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
package v2alpha1 | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/otterize/intents-operator/src/shared/errors" | ||
"github.com/otterize/intents-operator/src/shared/otterizecloud/graphqlclient" | ||
"github.com/otterize/intents-operator/src/shared/serviceidresolver/serviceidentity" | ||
"github.com/samber/lo" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/util/sets" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"strconv" | ||
) | ||
|
||
func init() { | ||
SchemeBuilder.Register(&ApprovedClientIntents{}, &ApprovedClientIntentsList{}) | ||
} | ||
|
||
//+kubebuilder:object:root=true | ||
//+kubebuilder:subresource:status | ||
|
||
// ApprovedClientIntents is the Schema for the intents API | ||
type ApprovedClientIntents struct { | ||
metav1.TypeMeta `json:",inline" yaml:",inline"` | ||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` | ||
|
||
Spec *IntentsSpec `json:"spec,omitempty" yaml:"spec,omitempty"` | ||
Status ApprovedClientIntentsStatus `json:"status,omitempty" yaml:"status,omitempty"` | ||
} | ||
|
||
// ApprovedClientIntentsList contains a list of ApprovedClientIntents | ||
type ApprovedClientIntentsList struct { | ||
metav1.TypeMeta `json:",inline" yaml:",inline"` | ||
metav1.ListMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` | ||
Items []ApprovedClientIntents `json:"items" yaml:"items"` | ||
} | ||
|
||
func init() { | ||
SchemeBuilder.Register(&ApprovedClientIntents{}, &ApprovedClientIntentsList{}) | ||
} | ||
|
||
func (in *ApprovedClientIntentsList) DeepCopyObject() runtime.Object { | ||
if c := in.DeepCopy(); c != nil { | ||
return c | ||
} | ||
return nil | ||
} | ||
|
||
type ApprovedClientIntentsStatus struct { | ||
// upToDate field reflects whether the client intents have successfully been applied | ||
// to the cluster to the state specified | ||
// +optional | ||
UpToDate bool `json:"upToDate"` | ||
// The last generation of the intents that was successfully reconciled. | ||
// +optional | ||
ObservedGeneration int64 `json:"observedGeneration"` | ||
// ResolvedIPs stores resolved IPs for a domain name - the network mapper populates it when DNS internetTarget is used | ||
// +optional | ||
ResolvedIPs []ResolvedIPs `json:"resolvedIPs,omitempty" yaml:"resolvedIPs,omitempty"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't forget to open a PR to update the mapper with this change + release them together |
||
} | ||
|
||
func (in *ApprovedClientIntents) GetWorkloadName() string { | ||
return in.Spec.Workload.Name | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetTargetList() []Target { | ||
return in.Spec.Targets | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetFilteredTargetList(intentTypes ...IntentType) []Target { | ||
return lo.Filter(in.GetTargetList(), func(item Target, index int) bool { | ||
for _, intentType := range intentTypes { | ||
if intentType == IntentTypeHTTP { | ||
if item.Kubernetes != nil && len(item.Kubernetes.HTTP) > 0 { | ||
return true | ||
} | ||
if item.Service != nil && len(item.Service.HTTP) > 0 { | ||
return true | ||
} | ||
} | ||
if intentType == IntentTypeKafka && item.Kafka != nil { | ||
return true | ||
} | ||
if intentType == IntentTypeDatabase && item.SQL != nil { | ||
return true | ||
} | ||
if intentType == IntentTypeAWS && item.AWS != nil { | ||
return true | ||
} | ||
if intentType == IntentTypeGCP && item.GCP != nil { | ||
return true | ||
} | ||
if intentType == IntentTypeAzure && item.Azure != nil { | ||
return true | ||
} | ||
if intentType == IntentTypeInternet && item.Internet != nil { | ||
return true | ||
} | ||
} | ||
return false | ||
}) | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetClientKind() string { | ||
if in.Spec.Workload.Kind == "" { | ||
return serviceidentity.KindOtterizeLegacy | ||
} | ||
return in.Spec.Workload.Kind | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetIntentsLabelMapping(requestNamespace string) map[string]string { | ||
otterizeAccessLabels := make(map[string]string) | ||
|
||
for _, intent := range in.GetTargetList() { | ||
if intent.IsTargetOutOfCluster() { | ||
continue | ||
} | ||
targetServiceIdentity := intent.ToServiceIdentity(requestNamespace) | ||
labelKey := fmt.Sprintf(OtterizeAccessLabelKey, targetServiceIdentity.GetFormattedOtterizeIdentityWithKind()) | ||
if intent.IsTargetServerKubernetesService() { | ||
labelKey = fmt.Sprintf(OtterizeSvcAccessLabelKey, targetServiceIdentity.GetFormattedOtterizeIdentityWithKind()) | ||
} | ||
otterizeAccessLabels[labelKey] = "true" | ||
} | ||
|
||
return otterizeAccessLabels | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetServersWithoutSidecar() (sets.Set[string], error) { | ||
if in.Annotations == nil { | ||
return sets.New[string](), nil | ||
} | ||
|
||
servers, ok := in.Annotations[OtterizeServersWithoutSidecarAnnotation] | ||
if !ok { | ||
return sets.New[string](), nil | ||
} | ||
|
||
serversList := make([]string, 0) | ||
err := json.Unmarshal([]byte(servers), &serversList) | ||
if err != nil { | ||
return nil, errors.Wrap(err) | ||
} | ||
|
||
return sets.New[string](serversList...), nil | ||
} | ||
|
||
func (in *ApprovedClientIntents) GetDatabaseIntents() []Target { | ||
return in.GetFilteredTargetList(IntentTypeDatabase) | ||
} | ||
|
||
func (in *ApprovedClientIntents) FromClientIntents(intents ClientIntents) { | ||
in.Name = intents.Name | ||
in.Namespace = intents.GetNamespace() | ||
in.Spec = intents.Spec | ||
} | ||
|
||
func (in *ApprovedClientIntentsList) FormatAsOtterizeIntents(ctx context.Context, k8sClient client.Client) ([]*graphqlclient.IntentInput, error) { | ||
otterizeIntents := make([]*graphqlclient.IntentInput, 0) | ||
for _, clientIntents := range in.Items { | ||
for _, intent := range clientIntents.GetTargetList() { | ||
clientServiceIdentity := clientIntents.ToServiceIdentity() | ||
input, err := intent.ConvertToCloudFormat(ctx, k8sClient, clientServiceIdentity) | ||
if err != nil { | ||
return nil, errors.Wrap(err) | ||
} | ||
statusInput, ok, err := approvedClientIntentsStatusToCloudFormat(clientIntents, intent) | ||
if err != nil { | ||
return nil, errors.Wrap(err) | ||
} | ||
|
||
input.Status = nil | ||
if ok { | ||
input.Status = statusInput | ||
} | ||
otterizeIntents = append(otterizeIntents, lo.ToPtr(input)) | ||
} | ||
} | ||
|
||
return otterizeIntents, nil | ||
} | ||
|
||
func approvedClientIntentsStatusToCloudFormat(approvedClientIntents ApprovedClientIntents, intent Target) (*graphqlclient.IntentStatusInput, bool, error) { | ||
status := graphqlclient.IntentStatusInput{ | ||
IstioStatus: &graphqlclient.IstioStatusInput{}, | ||
} | ||
|
||
serviceAccountName, ok := approvedClientIntents.Annotations[OtterizeClientServiceAccountAnnotation] | ||
if !ok { | ||
// Status is not set, nothing to do | ||
return nil, false, nil | ||
} | ||
|
||
status.IstioStatus.ServiceAccountName = toPtrOrNil(serviceAccountName) | ||
isSharedValue, ok := approvedClientIntents.Annotations[OtterizeSharedServiceAccountAnnotation] | ||
isShared := false | ||
if ok { | ||
parsedIsShared, err := strconv.ParseBool(isSharedValue) | ||
if err != nil { | ||
return nil, false, errors.Errorf("failed to parse shared service account annotation for client intents %s", approvedClientIntents.Name) | ||
} | ||
isShared = parsedIsShared | ||
} | ||
status.IstioStatus.IsServiceAccountShared = lo.ToPtr(isShared) | ||
|
||
clientMissingSidecarValue, ok := approvedClientIntents.Annotations[OtterizeMissingSidecarAnnotation] | ||
if !ok { | ||
return nil, false, errors.Errorf("missing annotation missing sidecar for client intents %s", approvedClientIntents.Name) | ||
} | ||
|
||
clientMissingSidecar, err := strconv.ParseBool(clientMissingSidecarValue) | ||
if err != nil { | ||
return nil, false, errors.Errorf("failed to parse missing sidecar annotation for client intents %s", approvedClientIntents.Name) | ||
} | ||
status.IstioStatus.IsClientMissingSidecar = lo.ToPtr(clientMissingSidecar) | ||
isServerMissingSidecar, err := approvedClientIntents.IsServerMissingSidecar(intent) | ||
if err != nil { | ||
return nil, false, errors.Wrap(err) | ||
} | ||
status.IstioStatus.IsServerMissingSidecar = lo.ToPtr(isServerMissingSidecar) | ||
return &status, true, nil | ||
} | ||
|
||
func (in *ApprovedClientIntents) IsServerMissingSidecar(intent Target) (bool, error) { | ||
serversSet, err := in.GetServersWithoutSidecar() | ||
if err != nil { | ||
return false, errors.Wrap(err) | ||
} | ||
identity := intent.ToServiceIdentity(in.Namespace) | ||
serverIdentity := identity.GetFormattedOtterizeIdentityWithoutKind() | ||
return serversSet.Has(serverIdentity), nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix comment?