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

[#2756] Apply config through the airy controller #3176

Merged
merged 13 commits into from
May 31, 2022

Conversation

ljupcovangelski
Copy link
Contributor

@ljupcovangelski ljupcovangelski commented May 18, 2022

addresses #2756

A draft PR for proof of concept and also to get some feedback 🙏 .

The CLI returns this:

$ airy config apply
Configured component  Enabled
security              true
sources-facebook      true
sources-google        true
integration-webhook   true

The endpoint accepts json

{
  "security": {
    "allowedOrigins": "*",
    "jwtSecret": "secret",
    "systemToken": "test"
  },
  "components": {
    "sources": {
      "facebook": {
        "token1": "token",
        "token2": "token"
      }
    }
  }
}

and also the legacy yaml format of the airy.yaml file.

@@ -1,15 +1,18 @@
load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
# gazelle:prefix github.com/airyhq/airy/lib/go/httpclient/payloads
# gazelle:prefix github.com/airyhq/airy/lib/go/payloads
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved the payloads outside of the httpclient package, because they are also used by the controller.

type ConfigComponent struct {
Removed bool `json:"removed"`
Component string `json:"component"`
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is currently only used by the ConfigApplyResponsePayload, so not sure if it should be here or in payloads. Also Removed is just to be in line with the current concept (when a configuration is applied without a component - that component is removed).

I'd be happy to remove this and add a separate endpoint for removing a component.

namespace := "default"
responseConfigComponents := payloads.ConfigApplyResponsePayload{}

err = json.Unmarshal(body, &conf)
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned I would suggest that we nest the config inside a data field. This will make the API more maintainable as we can add more options to the request body later when needed.

Copy link
Contributor

@juan-sebastian juan-sebastian May 18, 2022

Choose a reason for hiding this comment

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

Maybe having everything inside components. Also if we add more options specially mandatory options. That will create a breaking change anyway. Not sure having a nested value will be necessary

if len(secData) != 0 {
applyErr := k8s.ApplyConfigMap("security", namespace, secData, map[string]string{}, s.clientSet)
if applyErr != nil {
klog.Error("Unable to apply configuration for \"security\"\nError:\n" + err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

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

In this case, the request should fail and terminate early (same below)

Copy link
Contributor Author

@ljupcovangelski ljupcovangelski May 18, 2022

Choose a reason for hiding this comment

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

In this case, the request should fail and terminate early (same below)

I am not sure about this. The components are independent from each-other, so an error in deploying one component/configMap should not impact the ones that follow after.

We can return perhaps a list of failed components

Copy link
Contributor

Choose a reason for hiding this comment

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

It's true that we could do that but for clients, a completely failed state is easier to recover from than a state that is half failed.

What do you return for a request that only did 50% of what you asked it to? 200 aka "success"? In that case, clients may not be aware that anything failed at all

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I get it 👍 We can return the failed-components in a separate list, but I think as it is very unlikely that only one configMap fails - I will set it to return a 500 - InternalServerError.
From the UI I assume it will mostly be used for applying a single component at a time anyway.

infrastructure/controller/pkg/endpoints/cluster_apply.go Outdated Show resolved Hide resolved
@ljupcovangelski ljupcovangelski changed the title Feature/2756 config through controller [#2756] Apply config through the airy controller May 18, 2022
@ljupcovangelski ljupcovangelski force-pushed the feature/2756-config-through-controller branch 2 times, most recently from db4db7d to 537a769 Compare May 20, 2022 14:45
@ljupcovangelski ljupcovangelski force-pushed the feature/2756-config-through-controller branch from 537a769 to 0c62e5c Compare May 20, 2022 15:11

```json
{
"Security": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Payload needs to follow our snake_case convention

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Payload needs to follow our snake_case convention

Thanks 👍. I changed it for security and data. For the values which were in the airy.yaml (allowedOrigins, systemToken, jwtSecret, ...) I suggest we do it in a subsequent PR, as it has lots of changes across almost all components.

@ljupcovangelski ljupcovangelski marked this pull request as ready for review May 23, 2022 07:54
```json5
{
"security": {
"systemToken": "token",
Copy link
Contributor

Choose a reason for hiding this comment

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

We want to make this API the new source of truth for interacting with Airy. Therefore I'd argue that as with all other endpoints we also convert these keys into snake_case so that the interface is uniform.

The list of the deleted components is returned.

```json5
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete outer {} since this isn't valid json

}

var conf payloads.ComponentsUpdateRequestPayload
namespace := os.Getenv("NAMESPACE")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can use the variable that's already stored in s.namespace here

{
"name": "security",
"enabled": true,
"data": null
Copy link
Contributor

Choose a reason for hiding this comment

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

Can data ever be non-null? If no, then I'd remove it.

Also: security isn't a component

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we need another endpoint for applying the configuration forsecurity?

@juan-sebastian
Copy link
Contributor

I changed the cli part to use airy-controller endpoint. #3130

}

res := payloads.ComponentsUpdateResponsePayload{}
e := c.post("components.update", payload, &res)
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

Copy link
Contributor

Choose a reason for hiding this comment

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

I will fix this in my PR #3221

@ljupcovangelski
Copy link
Contributor Author

ljupcovangelski commented May 27, 2022

  • Added another endpoint for updating the general configuration of Airy Core - cluster.update. Currently only security can be configured, but we can use that endpoint to also update other generic configuration in the future.
  • airy config apply applies both components through components.update and the cluster config through cluster.update.
  • Components are deleted only by explicitly calling components.delete.
  • Added conversion for the security attributes and the components attributes to snake_case when posting to the API. The controller converts them back to lower_camel_case before writing the configuration, so this is compatible with the current airy.yaml file and the data that the components expect in the configMaps.
  • When a configMap is not applied, the endpoint returns 500, even though some of the configMaps might have applied successfully before that. We return a list of which configMaps were applied and which one failed, just in case this is needed on the client side.
  • Updated the docs

Copy link
Contributor

@juan-sebastian juan-sebastian left a comment

Choose a reason for hiding this comment

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

Look good. Juste some small things to adresse and it will be good to merge

infrastructure/controller/pkg/endpoints/cluster_update.go Outdated Show resolved Hide resolved
juan-sebastian
juan-sebastian previously approved these changes May 27, 2022
Copy link
Contributor

@juan-sebastian juan-sebastian left a comment

Choose a reason for hiding this comment

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

I did some minor changes it looks good now to me

@@ -17,7 +17,7 @@ type ClusterGet struct {
}

func (s *ClusterGet) ServeHTTP(w http.ResponseWriter, r *http.Request) {
components, err := configmaps.GetComponentsConfigMaps(r.Context(), s.namespace, s.clientSet, maskSecrets)
components, err := k8s.GetComponentsConfigMaps(r.Context(), s.namespace, s.clientSet, maskSecrets)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this actually work yet? 🤔 When I run the image in my local cluster this endpoint returns:

{"components":{}}

Or perhaps there is something more than add the image that I have to do :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this actually work yet? thinking When I run the image in my local cluster this endpoint returns:

{"components":{}}

Or perhaps there is something more than add the image that I have to do :)

You would also need to add the ingress rules.

Copy link
Contributor

Choose a reason for hiding this comment

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

This request is directly from within the cluster. If it was a networking issue the response would be a 404. Will do more testing later

ljupcovangelski and others added 2 commits May 30, 2022 11:01
Co-authored-by: Christoph Proeschel <chris@airy.co>
Copy link
Contributor

@juan-sebastian juan-sebastian left a comment

Choose a reason for hiding this comment

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

Perfect. great work!! Thanks for adding the label everywhere

@ljupcovangelski ljupcovangelski merged commit c7db4fe into develop May 31, 2022
@ljupcovangelski ljupcovangelski deleted the feature/2756-config-through-controller branch May 31, 2022 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants