Skip to content
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

feat: predefined configurableInterpreter #2768

Merged

Conversation

chaunceyjiang
Copy link
Member

Signed-off-by: chaunceyjiang chaunceyjiang@gmail.com

What type of PR is this?
/kind feature

What this PR does / why we need it:

Predefine ConfigurableInterpreter for some well-known third-party projects.

Which issue(s) this PR fixes:
Fixes #

Special notes for your reviewer:

Does this PR introduce a user-facing change?:

Predefine ConfigurableInterpreter for some well-known third-party projects.

@karmada-bot karmada-bot added the kind/feature Categorizes issue or PR as related to a new feature. label Nov 9, 2022
@karmada-bot karmada-bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Nov 9, 2022
@chaunceyjiang chaunceyjiang changed the title Predefined ConfigurableInterpreter [WIP] Predefined ConfigurableInterpreter Nov 9, 2022
@karmada-bot karmada-bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 9, 2022
@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from fa2cb96 to b639f25 Compare November 9, 2022 10:35
@chaunceyjiang
Copy link
Member Author

/cc @ikaven1024 @RainbowMango @XiShanYongYe-Chang

What do you think?

@ikaven1024
Copy link
Member

I do't understand what scene need this feature. Could you show a user case?

@chaunceyjiang
Copy link
Member Author

I do't understand what scene need this feature. Could you show a user case?

Currently, the built-in interpreter only maintains K8S resources. For some well-known third-party projects, Karmada may need to do some maintenance to reduce the cost of using the ConfigurableInterpreter.

For example, AggregateStatus may be a commonly used InterpreterOperation

@ikaven1024

@ikaven1024
Copy link
Member

I do't understand what scene need this feature. Could you show a user case?

Currently, the built-in interpreter only maintains K8S resources. For some well-known third-party projects, Karmada may need to do some maintenance to reduce the cost of using the ConfigurableInterpreter.

For example, AggregateStatus may be a commonly used InterpreterOperation

This interpreters are supplied by karmada, then why not implement them with go, just like built-in, rather than inefficient lua

@chaunceyjiang
Copy link
Member Author

why not implement them with go, just like built-in

Because if you use go to implement it, you need to introduce third-party project APIs, which will lead to more and more dependencies being introduced into Karmada.

@ikaven1024
Copy link
Member

why not implement them with go, just like built-in

Because if you use go to implement it, you need to introduce third-party project APIs, which will lead to more and more dependencies being introduced into Karmada.

We can use unstructed, no need import real APIs

@chaunceyjiang
Copy link
Member Author

We can use unstructed

This requires the maintainer of the third-party project to be familiar with the code of Karmada. On the other hand, this mechanism is convenient for the maintainer of the third-party project, not the maintainer of Kamrada.

@ikaven1024
Copy link
Member

We can use unstructed

This requires the maintainer of the third-party project to be familiar with the code of Karmada. On the other hand, this mechanism is convenient for the maintainer of the third-party project, not the maintainer of Kamrada.

That's say, these script files are committed by third-party project.

@chaunceyjiang
Copy link
Member Author

That's say, these script files are committed by third-party project.

Yes, Karmada maintainer or third-party project maintainer.

@RainbowMango RainbowMango added this to the v1.5 milestone Dec 8, 2022
@RainbowMango RainbowMango modified the milestones: v1.5, v1.6 Mar 7, 2023
@Poor12
Copy link
Member

Poor12 commented Mar 9, 2023

Hi @chaunceyjiang, would you like to keep this pr going? We have plans to integrate with some well-known projects. I think this pr is needed.

@chaunceyjiang
Copy link
Member Author

Hi @chaunceyjiang, would you like to keep this pr going?

Sure

@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from b639f25 to 7b86e50 Compare March 10, 2023 09:04
@chaunceyjiang
Copy link
Member Author

chaunceyjiang commented Mar 10, 2023

Directory Structure
resource_customizations
├── embed.go
├── webapp.my.domain                 # Group
│   └── v1                           # Version
│       └── Guestbook                # Kind
│           ├── customizations.yaml   # Fixed name
│           ├── customizations_test.yaml
│           └── testdata
└── webapp2.my.domain
    └── v1
        └── Guestbook
            ├── customizations.yaml
            ├── customizations_test.yaml
            └── testdata

customizations.yaml
# cat customizations.yaml 
apiVersion: config.karmada.io/v1alpha1
kind: ResourceInterpreterCustomization
metadata:
  name: customization
spec:
  target:
    apiVersion: apps/v1
    kind: Deployment
  customizations:
    retention:
      luaScript: >
        function Retain(desiredObj, runtimeObj)
          desiredObj.metadata.annotations.cluster = runtimeObj.metadata.annotations.cluster
          return desiredObj
        end
    replicaResource:
      luaScript: >
        function GetReplicas(obj)
          replica = obj.spec.replicas
          requirement = {
            resourceRequest = obj.spec.template.spec.containers[1].resources.limits,
            nodeClaim = {
              nodeSelector = obj.spec.template.spec.nodeSelector,
              tolerations = obj.spec.template.spec.tolerations
            }
          }
          return replica, requirement
        end
    replicaRevision:
      luaScript: >
        function ReviseReplica(obj, desiredReplica)
          obj.spec.replicas = desiredReplica
          return obj
        end
    statusReflection:
      luaScript: >
        function ReflectStatus(observedObj)
          return observedObj.status
        end
    statusAggregation:
      luaScript: >
        function AggregateStatus(desiredObj, items)
          desiredObj.status.readyReplicas = 0
          for i = 1, #items do
            desiredObj.status.readyReplicas = desiredObj.status.readyReplicas + items[i].status.readyReplicas
          end
          return desiredObj
        end
    healthInterpretation:
      luaScript: >
        function InterpretHealth(observedObj)
          return observedObj.status.readyReplicas == observedObj.spec.replicas
        end
    dependencyInterpretation:
      luaScript: >
        function GetDependencies(desiredObj)
          dependencies = {}
          dependencies[1] = {
            apiVersion = "v1",
            kind       = "ServiceAccount",
            name       = desiredObj.metadata.name,
            namespace  = desiredObj.metadata.namespace,
          }
          return dependencies
        end
---

apiVersion: config.karmada.io/v1alpha1
kind: ResourceInterpreterCustomization
metadata:
  name: customization-2
spec:
  target:
    apiVersion: apps/v1
    kind: Deployment
  customizations:
    dependencyInterpretation:
      luaScript: >
        function GetDependencies(desiredObj)
          dependencies = {}
          dependencies[1] = {
            apiVersion = "v1",
            kind       = "ConfigMap",
            name       = desiredObj.metadata.name,
            namespace  = desiredObj.metadata.namespace,
          }
          return dependencies
        end
---

Q: Why is such a directory structure set up, and what are the benefits of doing so?
A: First, it is easier to classify ResourceInterpreterCustomization for easy reference. Second, we can verify the content in customizations.yaml, just like karmada-webhook.

@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch 2 times, most recently from 9665531 to a2e4d6f Compare March 10, 2023 09:19
@chaunceyjiang
Copy link
Member Author

Does 1000 YAML files mean 1000 resources?

No, there will be some YAML files for testing one type of resource, and each type of resource has about 10 test files. So there are about 100 types of resources.

@RainbowMango
Copy link
Member

No, there will be some YAML files for testing one type of resource, and each type of resource has about 10 test files. So there are about 100 types of resources.

100 resources VS 1MB, is totally acceptable I guess.

@chaunceyjiang
Copy link
Member Author

100 resources VS 1MB, is totally acceptable I guess.

yes, i think so.

@chaunceyjiang
Copy link
Member Author

Can we organize the code like this?

Can the luavm directory be separated from configureinterpreter?

@RainbowMango
Copy link
Member

Can the luavm directory be separated from configureinterpreter?

I think keeping the luavm in pkg/resourceinterpreter/customized/declarative would be fine, at least it won't block this PR. Let's revisit during or after this PR.

@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from 73e4d20 to 5de9942 Compare April 4, 2023 03:14
@karmada-bot karmada-bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Apr 4, 2023
@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from 5de9942 to abf20ee Compare April 4, 2023 06:29
@Poor12
Copy link
Member

Poor12 commented Apr 4, 2023

Good job! Could you please post the latest test result(whether the built-in configurableInterpret takes effect and whether users can override the default third-party crds)?

@chaunceyjiang
Copy link
Member Author

chaunceyjiang commented Apr 4, 2023

build-in third-party configurableInterpreter:

image


users can override the third-party configurableInterpreter:

    statusAggregation:
      luaScript: >
        function AggregateStatus(desiredObj, statusItems)
          if statusItems == nil then
            return desiredObj
          end
          if desiredObj.status == nil then
            desiredObj.status = {}
          end
          if desiredObj.generation == nil then
            desiredObj.generation = 0
          end
          generation = desiredObj.generation
          replicas = 0
          updatedReplicas = 0 
          readyReplicas = 0
          availableReplicas = 0
          updatedReadyReplicas = 0
          expectedUpdatedReplicas = 0
          updateRevision = ''
          currentRevision = ''
          for i = 1, #statusItems do
            if statusItems[i].status ~= nil and statusItems[i].status.replicas ~= nil then
              replicas = replicas + statusItems[i].status.replicas
            end

            if statusItems[i].status ~= nil and statusItems[i].status.availableReplicas ~= nil then
              availableReplicas = availableReplicas + statusItems[i].status.availableReplicas
            end

          end
          desiredObj.status.observedGeneration = generation
          desiredObj.status.replicas = replicas
          desiredObj.status.updatedReplicas = updatedReplicas
          desiredObj.status.readyReplicas = readyReplicas
          desiredObj.status.availableReplicas = availableReplicas
          desiredObj.status.updatedReadyReplicas = updatedReadyReplicas
          desiredObj.status.expectedUpdatedReplicas = expectedUpdatedReplicas
          desiredObj.status.updateRevision = updateRevision
          desiredObj.status.currentRevision = currentRevision
          return desiredObj
        end

image

krmada control plane:

➤ k get clone -oyaml

image

@Poor12
Copy link
Member

Poor12 commented Apr 6, 2023

/lgtm

@karmada-bot karmada-bot added the lgtm Indicates that a PR is ready to be merged. label Apr 6, 2023
Copy link
Member

@XiShanYongYe-Chang XiShanYongYe-Chang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks~

if d.IsDir() {
return nil
}
if strings.Contains(d.Name(), "testdata") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is this going to happen?
Should we add a new document to describe how to use this feature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just to filter out test files.

pkg/resourceinterpreter/default/thirdparty/manager.go Outdated Show resolved Hide resolved
pkg/resourceinterpreter/default/thirdparty/manager.go Outdated Show resolved Hide resolved
pkg/resourceinterpreter/interpreter.go Outdated Show resolved Hide resolved
Copy link
Member

@RainbowMango RainbowMango left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I missed submitting my comments/questions...

resourcecustomizations/embed.go Outdated Show resolved Hide resolved
@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from abf20ee to c4d3726 Compare April 10, 2023 07:05
@karmada-bot karmada-bot removed the lgtm Indicates that a PR is ready to be merged. label Apr 10, 2023
…party projects.

Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
@chaunceyjiang chaunceyjiang force-pushed the predefinedConfigurableInterpreter branch from c4d3726 to 538d8f1 Compare April 10, 2023 07:22
Copy link
Member

@RainbowMango RainbowMango left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one question from me.
/assign @XiShanYongYe-Chang

Comment on lines +118 to +124
replica, requires, hookEnabled, err = i.thirdpartyInterpreter.GetReplicas(object)
if err != nil {
return
}
if hookEnabled {
return
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we put the thirdpartyInterpreter after the defaultInterpreter for better efficiency?
I think K8s native resources are used more often than third-party ones.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resources interpreted by thirdpartyInterpreter and thirdpartyInterpreter maybe not overlap, and I agree with this point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resources interpreted by thirdpartyInterpreter and thirdpartyInterpreter maybe not overlap

Yes, that's exactly what I was thinking.
@chaunceyjiang What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ReflectStatus of defaultInterpreter, if there is no built-in handler, it will attempt to collect the whole status from '.status' filed.

Refter to: https://github.com/karmada-io/karmada/blob/master/pkg/resourceinterpreter/default/native/default.go#L134-L135

If thirdpartyInterpreter is placed after defaultInterpreter, then the ReflectStatus of thirdpartyInterpreter will not take effect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainbowMango @XiShanYongYe-Chang What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If thirdpartyInterpreter is placed after defaultInterpreter, then the ReflectStatus of thirdpartyInterpreter will not take effect.

Good point!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that, thank you.

/approve

Copy link
Member

@XiShanYongYe-Chang XiShanYongYe-Chang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM.

@RainbowMango
Copy link
Member

/lgtm
Leave approve to @XiShanYongYe-Chang

@karmada-bot karmada-bot added the lgtm Indicates that a PR is ready to be merged. label Apr 11, 2023
@karmada-bot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: XiShanYongYe-Chang

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@karmada-bot karmada-bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 11, 2023
@karmada-bot karmada-bot merged commit 4133d59 into karmada-io:master Apr 11, 2023
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. kind/feature Categorizes issue or PR as related to a new feature. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants