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(convert): convert to KIC #1050

Merged
merged 20 commits into from
Feb 29, 2024
Merged

feat(convert): convert to KIC #1050

merged 20 commits into from
Feb 29, 2024

Conversation

Tieske
Copy link
Member

@Tieske Tieske commented Oct 10, 2023

New command "deck file kong2kic" Kong configuration file to Kong Ingress Controller manifests.

Currently, only ingress controller manifests are supported. Output format is always YAML.

Usage:
  deck file kong2kic [flags]

Flags:
  -f, --format string        output file format: json or yaml. (default "yaml")
  -h, --help                 help for kong2kic
  -o, --output-file string   Output file to write. Use - to write to stdout. (default "-")
  -s, --state string         decK file to process. Use - to read from stdin. (default "-")
      --style string         Generate manifests with annotations in Service and Ingress, or using the KongIngress CRD: annotation or crd. (default "annotation")
  • Global Plugins map to KongClusterPlugins
  • Kong Services map to K8s Services. Kong Routes map to K8s Ingresses. To specify Kong specific features, K8s Ingress and Service resources eventually have a KongIngress resource associated to them.
  • Kong Consumer entities map to KongConsumer manifests.

Jira: APIOPS-8

@mheap
Copy link
Member

mheap commented Oct 11, 2023

To specify Kong specific features, K8s Ingress and Service resources eventually have a KongIngress resource associated to them.

Most things in KongIngress have been moved to annotations on the Ingress. Can you share the list of KongIngress uses and we can help migrate to the annotation format

Copy link
Member

@mflendrich mflendrich left a comment

Choose a reason for hiding this comment

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

Discussed with @Tieske on zoom earlier today.

We concluded that there are two blockers / next steps for this PR:

  1. the implementation needs to avoid creating the deck <-> KIC dep cycle,
  2. more alignment (an approved product brief / design doc) is needed.

go.mod Outdated
@@ -19,6 +19,7 @@ require (
github.com/imdario/mergo v0.3.16
github.com/kong/go-apiops v0.1.21
github.com/kong/go-kong v0.46.0
github.com/kong/kubernetes-ingress-controller/v2 v2.11.1
Copy link
Member

Choose a reason for hiding this comment

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

This line is effectively adding a module dependency cycle between KIC and decK that we cannot make happen.

Since KIC uses decK as a library, it won't be possible for decK to import KIC as a module. A viable resolution for this would be:

  • introduction of an "umbrella" project over the existing decK that would decouple "deck-as-a-library" from "deck-as-a-tool" or
  • a massive refactor of deck or KIC.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The reason for this dependency is to make use of the API Schema definitions for KongClusterPlugin, KongConsumer, KongIngress, KongPlugin, etc. Would it be possible to extract the API Schema definitions into its own module that is imported by both deck and KIC? Similarly to what k8s does here: https://github.com/kubernetes/api

Copy link
Collaborator

Choose a reason for hiding this comment

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

Essentially, extract type definitions under https://github.com/Kong/kubernetes-ingress-controller/tree/main/pkg/apis/configuration into its own module.

Copy link
Member

Choose a reason for hiding this comment

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

The eng/PM decision reached is that we'll unblock deck2kic's dependency on KIC by implementing the proposal tracked by #1060.

@battlebyte
Copy link
Collaborator

To specify Kong specific features, K8s Ingress and Service resources eventually have a KongIngress resource associated to them.

Most things in KongIngress have been moved to annotations on the Ingress. Can you share the list of KongIngress uses and we can help migrate to the annotation format

Both styles (annotations-based and KongIngress-based) are supported in this implementation. By default it will generate an annotation-based output with no KongIngress entities. If the user is working with an older version of KIC and wants to generate a KongIngress-based output the flag "--style crd" can be used. By default "--style annotation".

@codecov-commenter
Copy link

codecov-commenter commented Nov 3, 2023

Codecov Report

Attention: 559 lines in your changes are missing coverage. Please review.

Comparison is base (a18140f) 5.58% compared to head (0c520fd) 21.52%.

Files Patch % Lines
kong2kic/route.go 67.08% 112 Missing and 19 partials ⚠️
cmd/file_kong2kic.go 0.00% 81 Missing ⚠️
kong2kic/consumer.go 71.37% 67 Missing and 6 partials ⚠️
kong2kic/writer.go 0.00% 56 Missing ⚠️
kong2kic/types.go 60.65% 34 Missing and 14 partials ⚠️
kong2kic/consumer_group.go 42.85% 30 Missing and 2 partials ⚠️
kong2kic/upstream.go 83.72% 24 Missing and 4 partials ⚠️
kong2kic/global_plugin.go 17.24% 23 Missing and 1 partial ⚠️
kong2kic/service.go 76.23% 16 Missing and 8 partials ⚠️
kong2kic/builder_v2_gw_api.go 57.14% 10 Missing and 5 partials ⚠️
... and 5 more
Additional details and impacted files
@@            Coverage Diff             @@
##            main    #1050       +/-   ##
==========================================
+ Coverage   5.58%   21.52%   +15.93%     
==========================================
  Files         36       53       +17     
  Lines       3884     5385     +1501     
==========================================
+ Hits         217     1159      +942     
- Misses      3650     4135      +485     
- Partials      17       91       +74     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Tieske
Copy link
Member Author

Tieske commented Jan 16, 2024

@mflendrich @GGabriele @battlebyte

I have cherry-picked the #1117 changes in here, rebased and fixed up.

Please give this another review. This should be close to merging now I think.

cmd/file_kong2kic.go Outdated Show resolved Hide resolved
cmd/file_kong2kic.go Outdated Show resolved Hide resolved
cmd/file_kong2kic.go Outdated Show resolved Hide resolved
cmd/file_kong2kic.go Outdated Show resolved Hide resolved
cmd/file_kong2kic.go Outdated Show resolved Hide resolved
kong2kic/types.go Outdated Show resolved Hide resolved
kong2kic/types.go Outdated Show resolved Hide resolved
GGabriele
GGabriele previously approved these changes Jan 22, 2024
Copy link
Collaborator

@GGabriele GGabriele left a comment

Choose a reason for hiding this comment

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

LGTM, but please get a +2 from someone from @Kong/team-k8s

@rainest
Copy link
Collaborator

rainest commented Jan 22, 2024

This line is effectively adding a module dependency cycle between KIC and decK that we cannot make happen.

Oh, this is what prompted that split? We were probably fine without that, the API packages are pretty isolated from the rest of the code and don't import any of the parser code that loads deck. The parser code does import the API, but that's just a duplicate leaf, not a cycle.

Rest of my review was mostly just looking over output-expected.yamls, since AFAIK the code's already been reviewed and we're mostly concerned with the end output. Dunno if we'd block this as-ism but we'll eventually need KIC 3.x upgrades and should add some additional tests to confirm that the config is valid.

Development concurrent with KIC 3.x bit us:

  • KongIngress still used. It looks like the one remaining one is for upstream configuration (the new Ingress annotations are used), which should be handled with KongUpstreamPolicy in 3.x.
  • Several resources (at least non-global KongPlugins and credential Secrets--I didn't review exhaustively) include kubernetes.io/ingress.class, which they don't actually use. Including it is benign though, it just won't actually do anything. Offhand it doesn't look like we have a complete list of which do and do not need it, so probably just ignore this.
  • Credential Secrets still use the kongCredType field instead of the new label. You can continue to include it for pre-3.0 compatibility but we will be removing support it within the next few 3.x releases.

Aside details, it looks like we just have expected output tests, not integration. Human review of large generated outputs will be error-prone, so I think we'd be better off tossing configuration into an actual instance to see if it's accepted. We have an existing KIC E2E test that'd serve as a good starting point because it runs the admission webhook and is basically self-contained (the test function spawns its own Kubernetes cluster and installs KIC+Kong; it doesn't require any additional setup), though we'd probably want to simplify the CI workflow a bit. With that we can have the test exec a kubectl apply to apply the output resources and check if the command fails (the webhook or static validation rejected something) or if a failure event shows up.

Copy link
Member

@mflendrich mflendrich left a comment

Choose a reason for hiding this comment

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

the API packages are pretty isolated from the rest of the code and don't import any of the parser code that loads deck. The parser code does import the API, but that's just a duplicate leaf, not a cycle.

This can work in the context of low-level package mechanics but stops working when we consider the larger-scale dependency hell problem. If we allowed KIC version X to pull in deck version Y pulling in KIC version Z, this would mean an (effectively) irreversible need to make coordinated changes in lockstep (between separately governed projects) from this point onwards. The opportunity cost of a dependency hell that we've avoided is the real win here, not "code compiles but it otherwise wouldn't".

To the point of the review:

  • Now that the deck<->KIC issue is resolved, my reason for "changes requested" is gone.
  • As Travis pointed out, KIC's API has evolved - KongIngress and kongCredType are deprecated as of KIC 3.0. This means that the proposed implementation will generate configuration that is considered deprecated and may cause validation warnings (+ will stop working in a future version of KIC). I think this issue is serious enough to fix in this PR, but I'll leave it to the APIOps folks so that we don't have too many cooks in the kitchen.
  • Not necessarily for this PR: Travis's point about testing. Our k8s integration testing experience is that with new k8s versions and KIC/Kong versions you'll be bumping into the "configuration that was working has stopped working" class of errors that will be missed (like we could have missed the KIC 3.0 API changes in the bullet point above). My (soft) review recommendation is what Travis says: instead of "golden output" testing, have an integration test involving KIC.

TL;DR:

  • the dependency blocker is gone, I'm removing my "changes requested"
  • did not review for code style/correctness
  • non-blocking (but very important) recommendation to upgrade the API to KIC 3.0+
  • non-blocking suggestion to consider integration testing

@mflendrich mflendrich dismissed their stale review January 23, 2024 10:58

the blocker (deck<->KIC dependency) is gone

@mheap
Copy link
Member

mheap commented Feb 13, 2024

@czeslavo I believe @battlebyte has made the requested changes. Could you take a final look and ✅ if you're happy?

@mheap
Copy link
Member

mheap commented Feb 13, 2024

Ah, I just noticed no additional commits on the branch. I couldn't see status in the docs examples and assumed that this was complete. @battlebyte Did you see Greg's comment above?

@mheap
Copy link
Member

mheap commented Feb 13, 2024

See #1218 for the implementation of all feedback

@Tieske
Copy link
Member Author

Tieske commented Feb 15, 2024

@czeslavo @battlebyte @GGabriele @mflendrich
This now incorporates the changes in #1218 . Should be good now, re-requested reviews, so please give it one more pass.

Then we can finally merge.

battlebyte
battlebyte previously approved these changes Feb 15, 2024
Copy link
Collaborator

@battlebyte battlebyte left a comment

Choose a reason for hiding this comment

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

Looks good to me!

@battlebyte
Copy link
Collaborator

This is the final command reference:

Convert Kong configuration files to Kong Ingress Controller (KIC) manifests.

The kong2kic subcommand transforms Kong's configuration files, written in the deck format, 
into Kubernetes manifests suitable for the Kong Ingress Controller. By default kong2kic generates 
manifests for KIC v3.x using the Kubernetes Gateway API. Only HTTP/HTTPS routes are supported.

Usage:
  deck file kong2kic [flags]

Flags:
      --class-name string    Value to use for "kubernetes.io/ingress.class" ObjectMeta.Annotations and for
                                        "parentRefs.name" in the case of HTTPRoute. (default "kong")
  -f, --format string        output file format: json or yaml. (default "yaml")
  -h, --help                 help for kong2kic
      --ingress              Use Kubernetes Ingress API manifests instead of Gateway API manifests.
      --kicv2                Generate manifests compatible with KIC v2.x.
  -o, --output-file string   Output file to write. Use - to write to stdout. (default "-")
  -s, --state string         decK file to process. Use - to read from stdin. (default "-")

@rspurgeon
Copy link
Collaborator

@battlebyte The only one of these I would consider altering is:

--kicv2                Generate manifests compatible with KIC v2.x.

Instead WDYT about --kic-version <version> with a default of 3 but allow a user to provide 2

@battlebyte
Copy link
Collaborator

@rspurgeon yes, that is something I considered as well. I'm fine changing it, no problem. Any thoughts on that @mheap ?

@mheap
Copy link
Member

mheap commented Feb 19, 2024 via email

@battlebyte
Copy link
Collaborator

@rspurgeon @mheap changed applied. New command reference:

Convert Kong configuration files to Kong Ingress Controller (KIC) manifests.

The kong2kic subcommand transforms Kong’s configuration files, written in the deck format, 
into Kubernetes manifests suitable for the Kong Ingress Controller. By default kong2kic generates 
manifests for KIC v3.x using the Kubernetes Gateway API. Only HTTP/HTTPS routes are supported.

Usage:
  deck file kong2kic [flags]

Flags:
      --class-name string    Value to use for "kubernetes.io/ingress.class" ObjectMeta.Annotations and for
                                        "parentRefs.name" in the case of HTTPRoute. (default "kong")
  -f, --format string        Output file format: json or yaml. (default "yaml")
  -h, --help                 help for kong2kic
      --ingress              Use Kubernetes Ingress API manifests instead of Gateway API manifests.
      --kic-version string   Generate manifests for KIC v3 or v2. Possible values are 2 or 3. (default "3")
  -o, --output-file string   Output file to write. Use - to write to stdout. (default "-")
  -s, --state string         decK file to process. Use - to read from stdin. (default "-")

@battlebyte battlebyte self-requested a review February 21, 2024 07:07
@mheap
Copy link
Member

mheap commented Feb 21, 2024

@GGabriele @czeslavo Could you please take a look? I'd like to get this released with the other changes on main

Copy link
Collaborator

@GGabriele GGabriele left a comment

Choose a reason for hiding this comment

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

Added a few comments / suggestions.

I haven't reviewed kong2kic/kong2kic.go though, I'll leave that to @czeslavo since I lack domain knowledge to properly do that.

cmd/file_kong2kic.go Show resolved Hide resolved
logbasics.Initialize(log.LstdFlags, verbosity)

// if cmdKong2KicVersion is not 2 or 3 return an error
if cmdKong2KicVersion != "2" && cmdKong2KicVersion != "3" {
Copy link
Collaborator

Choose a reason for hiding this comment

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

since you already have a validateInput helper function, it would make sense to consolidate all input validation there.


//
//
// Define the CLI data for the openapi2kong command
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// Define the CLI data for the openapi2kong command
// Define the CLI data for the kong2kic command

KongUpstreamPolicies []kicv1beta1.KongUpstreamPolicy `json:"upstreamPolicies,omitempty" yaml:",omitempty"`
}

func (k KICContent) marshalKICContentToYaml() ([]byte, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

are marshalKICContentToJSON and marshalKICContentToYaml the same except for the format used? If so, we should consolidate them into a single one:

func (k KICContent) marshalKICContentToFormat(format string) ([]byte, error) {
	var output []byte

	const (
		yamlSeparator = "---\n"
	)

	for _, kongIngress := range k.KongIngresses {
		kongIngresses, err := SerializeObjectDroppingFields(kongIngress, format)
		if err != nil {
			return nil, err
		}
		output = append(output, kongIngresses...)
		if format == file.YAML {
			output = append(output, []byte(yamlSeparator)...)
		}
	}
...
...
}

var c []byte
var err error

switch format {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't it possible to do the following instead? (untested)

	switch yamlOrJSON {
	case file.YAML:
		c, err = MarshalKongToKICYaml(content, string(format))
	case file.JSON:
		c, err = MarshalKongToKICJson(content, string(format))
	}
	if err != nil {
		return err
	}

var err error

switch format {
// case YAML:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Leftover comments?


if filename == "-" {
if _, err := fmt.Print(string(c)); err != nil {
return fmt.Errorf("writing file: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("writing file: %w", err)
return fmt.Errorf("writing to stdout: %w", err)

@battlebyte
Copy link
Collaborator

Thanks @GGabriele, all your suggestions applied in commit d49ecd0.

@GGabriele
Copy link
Collaborator

Thanks @GGabriele, all your suggestions applied in commit d49ecd0.

Much cleaner, thanks Jordi!

Copy link
Contributor

@czeslavo czeslavo left a comment

Choose a reason for hiding this comment

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

I left some comments. It's a massive volume of code to review and I'm not sure how deep we should go with the review here.

Note: Given this is not integration-tested, I wouldn't be very comfortable with advertising the functionality as something ready to use in prod. Are we going to implement tests that apply the resulting manifests to a K8s cluster with KIC running, ensuring all the routes work as expected before releasing it? If not, I think this should be advertised as an experimental feature.

kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic_test.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
kong2kic/kong2kic.go Outdated Show resolved Hide resolved
@mheap
Copy link
Member

mheap commented Feb 22, 2024

RE: Integration tests, I'm comfortable with manual testing for the initial release. We should add integration tests as a followup

@battlebyte
Copy link
Collaborator

Thanks @czeslavo, all your suggestions applied in commit ba63ef9. I'm currently working on integration testing using the kubernetes testing framework. I will ping you in Slack for your advice on how to best approach this if that is fine with you.

Copy link
Contributor

@czeslavo czeslavo left a comment

Choose a reason for hiding this comment

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

Thanks Jordi! Left some more about the missing continues where names are missing (objects without names will fail to be created).

kong2kic/service.go Outdated Show resolved Hide resolved
kong2kic/upstream.go Outdated Show resolved Hide resolved
kong2kic/upstream.go Outdated Show resolved Hide resolved
kong2kic/consumer_group.go Show resolved Hide resolved
kong2kic/route.go Outdated Show resolved Hide resolved
kong2kic/route.go Outdated Show resolved Hide resolved
kong2kic/service.go Outdated Show resolved Hide resolved
@battlebyte
Copy link
Collaborator

Thanks @czeslavo , missing continues fixed.

Copy link
Contributor

@czeslavo czeslavo left a comment

Choose a reason for hiding this comment

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

🚀

Copy link
Collaborator

@battlebyte battlebyte left a comment

Choose a reason for hiding this comment

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

Changes after review by Gabriele and Greg.

@Tieske Tieske merged commit 4743c24 into main Feb 29, 2024
39 checks passed
@Tieske Tieske deleted the kic branch February 29, 2024 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants