├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── SECURITY.md
├── dependabot-readme.md
├── dependabot.yml
└── workflows
│ ├── dependabot-go-mod-tidy.yml
│ ├── publish-doc.yaml
│ ├── validate-merge-queue-e2e-test.yaml
│ ├── validate-pull-request-golangci-lint.yaml
│ └── validate-pull-request-presubmit.yaml
├── .gitignore
├── .golangci.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── NOTICE
├── PROJECT
├── README.md
├── cmd
└── aws-application-networking-k8s
│ └── main.go
├── code-of-conduct.md
├── config
├── crds
│ ├── bases
│ │ ├── application-networking.k8s.aws_accesslogpolicies.yaml
│ │ ├── application-networking.k8s.aws_iamauthpolicies.yaml
│ │ ├── application-networking.k8s.aws_serviceexports.yaml
│ │ ├── application-networking.k8s.aws_serviceimports.yaml
│ │ ├── application-networking.k8s.aws_targetgrouppolicies.yaml
│ │ ├── application-networking.k8s.aws_vpcassociationpolicies.yaml
│ │ ├── externaldns.k8s.io_dnsendpoints.yaml
│ │ └── gateway.networking.k8s.io_tlsroutes.yaml
│ └── kustomization.yaml
├── default
│ ├── kustomization.yaml
│ ├── manager_auth_proxy_patch.yaml
│ └── manager_config_patch.yaml
├── iam
│ └── recommended-inline-policy.json
├── manager
│ ├── controller_manager_config.yaml
│ ├── kustomization.yaml
│ └── manager.yaml
├── overlays
│ └── namespaced
│ │ ├── kustomization.yaml
│ │ ├── role-binding.json
│ │ └── role.json
├── prometheus
│ ├── kustomization.yaml
│ └── monitor.yaml
├── rbac
│ ├── auth_proxy_client_clusterrole.yaml
│ ├── auth_proxy_role.yaml
│ ├── auth_proxy_role_binding.yaml
│ ├── auth_proxy_service.yaml
│ ├── cluster-role-binding.yaml
│ ├── cluster-role-controller.yaml
│ ├── kustomization.yaml
│ └── service-account.yaml
└── webhook
│ ├── kustomization.yaml
│ └── manifests.yaml
├── docgen
├── .gitignore
├── README.md
├── api-reference-base.md
├── config.json
└── template
│ ├── members.tpl
│ ├── pkg.tpl
│ ├── placeholder.go
│ └── type.tpl
├── docs
├── api-reference.md
├── api-types
│ ├── access-log-policy.md
│ ├── gateway.md
│ ├── grpc-route.md
│ ├── http-route.md
│ ├── iam-auth-policy.md
│ ├── service-export.md
│ ├── service-import.md
│ ├── service.md
│ ├── target-group-policy.md
│ ├── tls-route.md
│ └── vpc-association-policy.md
├── concepts
│ ├── concepts.md
│ └── overview.md
├── conformance-test.md
├── contributing
│ ├── developer-cheat-sheet.md
│ └── developer.md
├── faq.md
├── guides
│ ├── advanced-configurations.md
│ ├── custom-domain-name.md
│ ├── deploy.md
│ ├── environment.md
│ ├── getstarted.md
│ ├── grpc.md
│ ├── https.md
│ ├── pod-readiness-gates.md
│ ├── ram-sharing.md
│ ├── tls-passthrough.md
│ └── upgrading-v1-0-x-to-v1-1-y.md
├── images
│ ├── GatewayUserGuideFigures.pptx
│ ├── accept-resource-share.png
│ ├── controller.png
│ ├── example1.png
│ ├── example2.png
│ ├── fundamentals-mapping.png
│ ├── kubernetes_icon.svg
│ ├── multi-cluster.png
│ ├── personae.png
│ ├── resource-share1.png
│ ├── resource-share2.png
│ ├── resource-share3.png
│ ├── resource-share4.png
│ ├── resource-share5.png
│ ├── resource-share6.png
│ ├── service-network.png
│ ├── service.png
│ ├── serviceimport.png
│ └── tlsroute-multi-cluster.png
├── index.md
└── overrides
│ └── home.html
├── files
├── controller-installation
│ ├── deploy-namesystem.yaml
│ ├── deploy-v1.0.4.yaml
│ ├── deploy-v1.0.6.yaml
│ ├── deploy-v1.0.7.yaml
│ ├── deploy-v1.1.0.yaml
│ ├── deploy-v1.1.1.yaml
│ ├── gatewayclass.yaml
│ └── recommended-inline-policy.json
└── examples
│ ├── greeter-grpc-route.yaml
│ ├── greeter-grpc-server.yaml
│ ├── inventory-route-bluegreen.yaml
│ ├── inventory-route.yaml
│ ├── inventory-ver1.yaml
│ ├── inventory-ver2-export.yaml
│ ├── inventory-ver2-import.yaml
│ ├── inventory-ver2.yaml
│ ├── my-gateway-tls-passthrough.yaml
│ ├── my-gateway.yaml
│ ├── my-hotel-gateway-multi-listeners.yaml
│ ├── my-hotel-gateway.yaml
│ ├── my-httproute.yaml
│ ├── nginx-server-tls-passthrough.yaml
│ ├── parking.yaml
│ ├── rate-route-path.yaml
│ ├── rate-tlsroute-bluegreen.yaml
│ ├── review.yaml
│ ├── service-1-export.yaml
│ ├── service-1-import.yaml
│ ├── service-1.yaml
│ ├── service-2-export.yaml
│ ├── service-2-import.yaml
│ ├── service-2.yaml
│ ├── tls-rate1.yaml
│ ├── tls-rate2-export.yaml
│ ├── tls-rate2-import.yaml
│ ├── tls-rate2-targetgrouppolicy.yaml
│ ├── tls-rate2.yaml
│ └── tlsroute-nginx.yaml
├── go.mod
├── go.sum
├── hack
└── boilerplate.go.txt
├── helm
├── Chart.yaml
├── crds
│ ├── application-networking.k8s.aws_accesslogpolicies.yaml
│ ├── application-networking.k8s.aws_iamauthpolicies.yaml
│ ├── application-networking.k8s.aws_serviceexports.yaml
│ ├── application-networking.k8s.aws_serviceimports.yaml
│ ├── application-networking.k8s.aws_targetgrouppolicies.yaml
│ ├── application-networking.k8s.aws_vpcassociationpolicies.yaml
│ ├── externaldns.k8s.io_dnsendpoints.yaml
│ └── gateway.networking.k8s.io_tlsroutes.yaml
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── cluster-role-binding.yaml
│ ├── cluster-role-controller.yaml
│ ├── deployment.yaml
│ ├── metrics-service.yaml
│ ├── pdb.yaml
│ ├── service-account.yaml
│ └── webhook.yaml
├── values.schema.json
└── values.yaml
├── mkdocs.yml
├── mocks
└── controller-runtime
│ └── client
│ ├── client_mocks.go
│ ├── generate.go
│ └── record_mock.go
├── pkg
├── apis
│ └── applicationnetworking
│ │ └── v1alpha1
│ │ ├── accesslogpolicy_types.go
│ │ ├── authpolicy_types.go
│ │ ├── common.go
│ │ ├── common_test.go
│ │ ├── doc.go
│ │ ├── generated.register.go
│ │ ├── serviceexport_types.go
│ │ ├── serviceimport_types.go
│ │ ├── targetgrouppolicy_types.go
│ │ ├── vpcassociationpolicy_types.go
│ │ └── zz_generated.deepcopy.go
├── aws
│ ├── cloud.go
│ ├── cloud_mocks.go
│ ├── cloud_test.go
│ ├── metrics
│ │ ├── collector.go
│ │ ├── collector_test.go
│ │ └── instruments.go
│ └── services
│ │ ├── tagging.go
│ │ ├── tagging_mocks.go
│ │ ├── tagging_test.go
│ │ ├── vpclattice.go
│ │ ├── vpclattice_mocks.go
│ │ └── vpclattice_test.go
├── config
│ ├── controller_config.go
│ ├── controller_config_test.go
│ └── ec2_metadata.go
├── controllers
│ ├── accesslogpolicy_controller.go
│ ├── errors.go
│ ├── eventhandlers
│ │ ├── gateway.go
│ │ ├── gatewayclass.go
│ │ ├── mapper.go
│ │ ├── mapper_test.go
│ │ ├── service.go
│ │ ├── service_test.go
│ │ ├── serviceimport.go
│ │ ├── serviceimport_test.go
│ │ └── vpc_association_policy.go
│ ├── gateway_controller.go
│ ├── gatewayclass_controller.go
│ ├── iamauthpolicy_controller.go
│ ├── iamauthpolicy_controller_test.go
│ ├── pod_controller.go
│ ├── route_controller.go
│ ├── route_controller_test.go
│ ├── service_controller.go
│ ├── serviceexport_controller.go
│ ├── serviceimport_controller.go
│ ├── suite_test.go
│ ├── targetgrouppolicy_controller.go
│ └── vpcassociationpolicy_controller.go
├── deploy
│ ├── externaldns
│ │ ├── dnsendpoint_manager.go
│ │ ├── dnsendpoint_manager_mock.go
│ │ └── dnsendpoint_manager_test.go
│ ├── lattice
│ │ ├── access_log_subscription_manager.go
│ │ ├── access_log_subscription_manager_mock.go
│ │ ├── access_log_subscription_manager_test.go
│ │ ├── access_log_subscription_synthesizer.go
│ │ ├── access_log_subscription_synthesizer_test.go
│ │ ├── config_test.go
│ │ ├── error.go
│ │ ├── iamauthpolicy_manager.go
│ │ ├── iamauthpolicy_manager_test.go
│ │ ├── listener_manager.go
│ │ ├── listener_manager_mock.go
│ │ ├── listener_manager_test.go
│ │ ├── listener_synthesizer.go
│ │ ├── listener_synthesizer_test.go
│ │ ├── rule_manager.go
│ │ ├── rule_manager_mock.go
│ │ ├── rule_manager_test.go
│ │ ├── rule_synthesizer.go
│ │ ├── rule_synthesizer_test.go
│ │ ├── service_manager.go
│ │ ├── service_manager_mock.go
│ │ ├── service_manager_test.go
│ │ ├── service_network_manager.go
│ │ ├── service_network_manager_mock.go
│ │ ├── service_network_manager_test.go
│ │ ├── service_synthesizer.go
│ │ ├── service_synthesizer_test.go
│ │ ├── target_group_manager.go
│ │ ├── target_group_manager_mock.go
│ │ ├── target_group_manager_test.go
│ │ ├── target_group_synthesizer.go
│ │ ├── target_group_synthesizer_test.go
│ │ ├── targets_manager.go
│ │ ├── targets_manager_mock.go
│ │ ├── targets_manager_test.go
│ │ ├── targets_synthesizer.go
│ │ └── targets_synthesizer_test.go
│ ├── stack_deployer.go
│ ├── stack_deployer_test.go
│ ├── stack_marshaller.go
│ └── stack_schema_builder.go
├── gateway
│ ├── model_build_access_log_subscription.go
│ ├── model_build_access_log_subscription_test.go
│ ├── model_build_lattice_service.go
│ ├── model_build_lattice_service_mock.go
│ ├── model_build_lattice_service_test.go
│ ├── model_build_listener.go
│ ├── model_build_listener_test.go
│ ├── model_build_rule.go
│ ├── model_build_rule_test.go
│ ├── model_build_targetgroup.go
│ ├── model_build_targetgroup_mock.go
│ ├── model_build_targetgroup_test.go
│ ├── model_build_targets.go
│ └── model_build_targets_test.go
├── k8s
│ ├── events.go
│ ├── finalizer.go
│ ├── finalizer_mock.go
│ ├── policyhelper
│ │ ├── kind.go
│ │ ├── kind_test.go
│ │ ├── policy.go
│ │ └── policy_test.go
│ └── utils.go
├── model
│ ├── core
│ │ ├── fake_resource.go
│ │ ├── graph
│ │ │ ├── resource_graph.go
│ │ │ ├── resource_graph_test.go
│ │ │ └── typological_traversal.go
│ │ ├── grpcroute.go
│ │ ├── grpcroute_test.go
│ │ ├── httproute.go
│ │ ├── httproute_test.go
│ │ ├── policy.go
│ │ ├── resource.go
│ │ ├── route.go
│ │ ├── stack.go
│ │ ├── stack_id.go
│ │ ├── stack_mock.go
│ │ ├── stack_test.go
│ │ ├── tlsroute.go
│ │ ├── tlsroute_test.go
│ │ ├── token_types.go
│ │ └── token_types_test.go
│ └── lattice
│ │ ├── accesslogsubscription.go
│ │ ├── iamauthpolicy.go
│ │ ├── listener.go
│ │ ├── rule.go
│ │ ├── service.go
│ │ ├── servicenetwork.go
│ │ ├── targetgroup.go
│ │ ├── targets.go
│ │ └── types.go
├── runtime
│ ├── errors.go
│ └── reconcile.go
├── utils
│ ├── common.go
│ ├── common_test.go
│ ├── condition.go
│ ├── gwlog
│ │ ├── actions.go
│ │ ├── gwlog.go
│ │ ├── metadata.go
│ │ └── metadata_test.go
│ ├── pod_condition.go
│ ├── priority_queue.go
│ ├── retry
│ │ ├── backoff.go
│ │ ├── errors.go
│ │ └── retry.go
│ └── ttime
│ │ └── ttime.go
└── webhook
│ ├── core
│ ├── context.go
│ ├── context_test.go
│ ├── mutating_handler.go
│ ├── mutating_handler_test.go
│ ├── mutator.go
│ └── mutator_mocks.go
│ ├── pod_mutator.go
│ ├── pod_mutator_test.go
│ └── pod_readiness_gate_injector.go
├── requirements.txt
├── scripts
├── gen-webhook-secret.sh
├── github-release.sh
├── lib
│ ├── aws.sh
│ ├── common.sh
│ ├── config.sh
│ ├── logging.sh
│ └── login.sh
├── load_env_variables.sh
├── patch-deploy-yaml.sh
├── release-controller.sh
└── setup.sh
└── test
├── go.mod
├── go.sum
├── pkg
└── test
│ ├── context.go
│ ├── framework.go
│ ├── gateway.go
│ ├── grpc_helloworld.go
│ ├── grpcbin.go
│ ├── grpcroute.go
│ ├── grpcurl_runner.go
│ ├── header_match_httproute.go
│ ├── httpapp.go
│ ├── httproute.go
│ ├── httpsapp.go
│ ├── metadata.go
│ ├── method_match_httproute.go
│ ├── nginxapp.go
│ ├── path_match_httproute.go
│ ├── pod_manager.go
│ ├── service_export_import.go
│ ├── target_group_policy.go
│ ├── tlsroute.go
│ └── weighted_routing_httproute.go
└── suites
├── integration
├── access_log_policy_test.go
├── byoc_test.go
├── defined_target_ports_test.go
├── delete_target_groups_test.go
├── grpcroute_test.go
├── httproute_creation_test.go
├── httproute_header_match_test.go
├── httproute_method_match_test.go
├── httproute_mutation_do_not_leak_target_group_test.go
├── httproute_path_match_test.go
├── httproute_rule_priority_test.go
├── httproute_update_test.go
├── https_listener_weighted_rule_with_service_export_import_test.go
├── iamauthpolicy_test.go
├── ram_share_test.go
├── readiness_gate_test.go
├── serviceexport_mutation_test.go
├── suite_test.go
├── target_group_policy_test.go
├── tlsroute_serviceexport_test.go
├── tlsroute_test.go
└── vpc_association_policy_test.go
└── webhook
├── readiness_gate_inject_test.go
└── suite_test.go
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
29 | **Possible Solution**
30 | If you have any ideas on how to solve the issue, please describe them here.
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 | **What type of PR is this?**
11 |
12 |
19 |
20 | **Which issue does this PR fix**:
21 |
22 |
23 | **What does this PR do / Why do we need it**:
24 |
25 |
26 | **If an issue # is not available please add repro steps and logs from aws-gateway-controller showing the issue**:
27 |
28 |
29 | **Testing done on this change**:
30 |
34 |
35 | **Automation added to e2e**:
36 |
40 |
41 | **Will this PR introduce any new dependencies?**:
42 |
45 |
46 | **Will this break upgrades or downgrades. Has updating a running cluster been tested?**:
47 |
48 | **Does this PR introduce any user-facing change?**:
49 |
54 |
55 | ```release-note
56 |
57 | ```
58 |
59 | **Do all end-to-end tests successfully pass when running `make e2e-test`?**:
60 |
63 | ```
64 |
65 | ```
66 |
67 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | ## Reporting Security Issues
2 |
3 | We take all security reports seriously.
4 | When we receive such reports,
5 | we will investigate and subsequently address
6 | any potential vulnerabilities as quickly as possible.
7 | If you discover a potential security issue in this project,
8 | please notify AWS/Amazon Security via our
9 | [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/)
10 | or directly via email to [AWS Security](mailto:aws-security@amazon.com).
11 | Please do *not* create a public GitHub issue in this project.
12 |
13 |
--------------------------------------------------------------------------------
/.github/dependabot-readme.md:
--------------------------------------------------------------------------------
1 | # Dependabot Configuration for Go Modules
2 |
3 | This repository is configured to use Dependabot for automated dependency updates with `go mod tidy` support.
4 |
5 | ## Configuration Files
6 |
7 | 1. `.github/dependabot.yml` - Configures Dependabot to check for Go module updates weekly
8 | 2. `.github/workflows/dependabot-go-mod-tidy.yml` - GitHub Actions workflow that runs `go mod tidy` on Dependabot PRs
9 |
10 | ## How It Works
11 |
12 | 1. Dependabot creates PRs to update Go dependencies according to the schedule in `dependabot.yml`
13 | 2. When a PR is created that modifies `go.mod` or `go.sum`, the workflow is triggered
14 | 3. The workflow checks if the PR was created by Dependabot
15 | 4. If so, it runs `go mod tidy` and commits any changes back to the PR
16 |
17 | ## Required Repository Settings
18 |
19 | For the workflow to function properly, you need to configure the repository to allow Dependabot to trigger workflows with write permissions:
20 |
21 | 1. Go to the repository on GitHub
22 | 2. Navigate to Settings > Code and automation > Actions > General
23 | 3. Scroll down to "Workflow permissions"
24 | 4. Enable "Read and write permissions"
25 | 5. Check "Allow GitHub Actions to create and approve pull requests"
26 | 6. Save changes
27 |
28 | Additionally, you need to configure Dependabot to have write access to PRs:
29 |
30 | 1. Go to the repository on GitHub
31 | 2. Navigate to Settings > Code and automation > Actions > General
32 | 3. Scroll down to "Workflow permissions from pull requests"
33 | 4. Select "Allow Dependabot to run workflows"
34 | 5. Save changes
35 |
36 | ## Troubleshooting
37 |
38 | If the workflow isn't running or isn't able to commit changes:
39 |
40 | 1. Check that the repository settings are configured as described above
41 | 2. Verify that the PR was created by Dependabot
42 | 3. Check the workflow run logs for any errors
43 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "gomod"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | ignore:
8 | - dependency-name: "*"
9 | update-types: ["version-update:semver-patch"]
10 | commit-message:
11 | prefix: "chore"
12 | include: "scope"
13 | labels:
14 | - "dependencies"
15 | - "go"
16 |
17 | - package-ecosystem: "gomod"
18 | directory: "/test"
19 | schedule:
20 | interval: "weekly"
21 | ignore:
22 | - dependency-name: "*"
23 | update-types: ["version-update:semver-patch"]
24 | commit-message:
25 | prefix: "chore"
26 | include: "scope"
27 | labels:
28 | - "dependencies"
29 | - "go"
--------------------------------------------------------------------------------
/.github/workflows/dependabot-go-mod-tidy.yml:
--------------------------------------------------------------------------------
1 | name: Dependabot Go Mod Tidy
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - 'go.mod'
7 | - 'go.sum'
8 |
9 | permissions:
10 | contents: write
11 | pull-requests: write
12 |
13 | jobs:
14 | go-mod-tidy:
15 | runs-on: ubuntu-latest
16 | if: ${{ github.actor == 'dependabot[bot]' }}
17 | steps:
18 | - name: Checkout code
19 | uses: actions/checkout@v3
20 | with:
21 | ref: ${{ github.head_ref }}
22 | token: ${{ secrets.GITHUB_TOKEN }}
23 |
24 | - name: Setup Go
25 | uses: actions/setup-go@v4
26 | with:
27 | go-version: '1.x'
28 |
29 | - name: Run go mod tidy
30 | run: |
31 | go mod tidy
32 |
33 | - name: Check for changes
34 | id: git-check
35 | run: |
36 | git status --porcelain
37 | if [ -n "$(git status --porcelain)" ]; then
38 | echo "changes=true" >> $GITHUB_OUTPUT
39 | else
40 | echo "changes=false" >> $GITHUB_OUTPUT
41 | fi
42 |
43 | - name: Commit and push changes
44 | if: steps.git-check.outputs.changes == 'true'
45 | run: |
46 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
47 | git config --local user.name "github-actions[bot]"
48 | git add go.mod go.sum
49 | git commit -m "Run go mod tidy for Dependabot PR"
50 | git push
51 |
--------------------------------------------------------------------------------
/.github/workflows/publish-doc.yaml:
--------------------------------------------------------------------------------
1 | name: publish-doc
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - 'release-v*.*.*'
8 | permissions:
9 | contents: write
10 | jobs:
11 | publish-docs:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0
17 | persist-credentials: true
18 | - name: Set up Python
19 | uses: actions/setup-python@v4
20 | with:
21 | python-version: '3.x'
22 | - name: Configure git
23 | run: |
24 | git config --global user.email "ci-bot@amazon.com"
25 | git config --global user.name "ci-bot"
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | pip install mkdocs-material mike
30 | - name: Deploy to Mike
31 | run: |
32 | if [[ ${{ github.ref }} == refs/heads/main ]]; then
33 | # Deploy to the mike doc version `dev` and update the `latest` alias for the main branch new git commits
34 | mike deploy dev latest --update-aliases --push
35 | mike set-default latest
36 | elif [[ ${{ github.ref }} == refs/heads/release-v* ]]; then
37 | # Deploy to the mike doc version `vx.x.x` for the new git branches `release-vx.x.x`
38 | branch_name=${{ github.ref }}
39 | version=${branch_name##refs/heads/release-}
40 | mike deploy $version --push
41 | fi
42 |
--------------------------------------------------------------------------------
/.github/workflows/validate-pull-request-golangci-lint.yaml:
--------------------------------------------------------------------------------
1 | name: Validate pull request with golangci-lint before putting into queue
2 | permissions:
3 | id-token: write
4 | contents: read
5 | on:
6 | pull_request:
7 | jobs:
8 | validate:
9 | name: golangci-lint
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | - run: sed -En 's/^go[[:space:]]+([[:digit:].]+)$/GO_VERSION=\1/p' go.mod >> $GITHUB_ENV
14 | - uses: actions/setup-go@v4
15 | with:
16 | go-version: ${{ env.GO_VERSION }}
17 | cache: false
18 | - name: golangci-lint
19 | uses: golangci/golangci-lint-action@v3
20 | with:
21 | version: v1.63.4
22 | args: --verbose --timeout 30m
--------------------------------------------------------------------------------
/.github/workflows/validate-pull-request-presubmit.yaml:
--------------------------------------------------------------------------------
1 | name: Validate pull request with presubmit before putting into queue
2 | on:
3 | pull_request:
4 | jobs:
5 | validate:
6 | runs-on: ubuntu-latest
7 | env:
8 | K8S_VERSION: ${{ matrix.k8sVersion }}
9 | steps:
10 | - uses: actions/checkout@v3
11 | - run: sed -En 's/^go[[:space:]]+([[:digit:].]+)$/GO_VERSION=\1/p' go.mod >> $GITHUB_ENV
12 | - uses: actions/setup-python@v4
13 | with:
14 | python-version: '3.11'
15 | cache: 'pip'
16 | - run: pip install -r requirements.txt
17 | - uses: actions/setup-go@v3
18 | with:
19 | go-version: ${{ env.GO_VERSION }}
20 | check-latest: true
21 | - uses: actions/cache@v4
22 | with:
23 | path: |
24 | ~/.cache/go-build
25 | ~/go/pkg/mod
26 | ~/go/bin/
27 | ~/.kubebuilder/bin
28 | key: ${{ runner.os }}-go-cache-${{ hashFiles('**/go.sum') }}
29 | - run: go install github.com/golang/mock/mockgen@v1.6.0
30 | - run: go install sigs.k8s.io/kustomize/kustomize/v5@v5.6.0
31 | - run: go install sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-20220421205612-c162794a9b12
32 | - run: go install github.com/mattn/goveralls@b031368
33 | - run: make manifest
34 | - run: make vet
35 | - run: make test
36 | - run: make docs
37 | - name: Send coverage
38 | env:
39 | COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 | run: goveralls -coverprofile=coverage.out -service=github
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Keep this until the APIs upstreamed
2 | coverage.out
3 | deploy.yaml
4 |
5 | # MkDocs documentation
6 | site*/
7 |
8 | # Multi-module go project
9 | go.work*
10 |
11 | # envFile from load_env_variables.sh
12 | **/envFile
13 |
14 | # IDE files/directories
15 | .idea/
16 |
17 | # gomock generated prog.go
18 | pkg/aws/services/gomock_reflect_*
19 | mocks/controller-runtime/client/gomock_reflect_*
20 | pkg/**/prog.*
21 |
22 | # Image build tarballed bundles
23 | *.tgz
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | linters:
3 | disable:
4 | - errcheck
5 | exclusions:
6 | generated: lax
7 | presets:
8 | - comments
9 | - common-false-positives
10 | - legacy
11 | - std-error-handling
12 | paths:
13 | - third_party$
14 | - builtin$
15 | - examples$
16 | rules:
17 | - linters:
18 | - staticcheck
19 | text: "ST1012:"
20 | - linters:
21 | - staticcheck
22 | text: "QF1003:"
23 | - linters:
24 | - staticcheck
25 | text: "QF1001:"
26 | formatters:
27 | exclusions:
28 | generated: lax
29 | paths:
30 | - third_party$
31 | - builtin$
32 | - examples$
33 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the manager binary
2 | FROM --platform=$BUILDPLATFORM golang:1.23.6 as builder
3 |
4 | WORKDIR /workspace
5 | # Copy the Go Modules manifests
6 | COPY go.mod go.mod
7 | COPY go.sum go.sum
8 |
9 | # cache deps before building and copying source so that we don't need to re-download as much
10 | # and so that source changes don't invalidate our downloaded layer
11 | #RUN go mod download
12 | RUN GOPROXY=direct go mod download
13 |
14 | # Copy the go source
15 | COPY cmd/aws-application-networking-k8s/main.go main.go
16 | COPY pkg/ pkg/
17 | COPY scripts scripts
18 |
19 | ARG TARGETOS
20 | ARG TARGETARCH
21 |
22 | # Build
23 | RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -a -o manager main.go
24 |
25 | # Use distroless as minimal base image to package the manager binary
26 | # Refer to https://github.com/GoogleContainerTools/distroless for more details
27 | FROM --platform=$TARGETPLATFORM gcr.io/distroless/static:nonroot
28 | WORKDIR /
29 | COPY --from=builder /workspace/manager .
30 | USER 65532:65532
31 |
32 | ENTRYPOINT ["/manager"]
33 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
--------------------------------------------------------------------------------
/PROJECT:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/PROJECT
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS Gateway API Controller for VPC Lattice
2 |
3 |
4 |
5 |
6 |
7 |
8 | AWS Application Networking is an implementation of the Kubernetes [Gateway API](https://gateway-api.sigs.k8s.io/). This project is designed to run in a Kubernetes cluster and orchestrates AWS VPC Lattice resources using Kubernetes Custom Resource Definitions like Gateway and HTTPRoute.
9 |
10 | ## Documentation
11 |
12 | ### Website
13 |
14 | The API specification and detailed documentation is available on the project
15 | website: [https://www.gateway-api-controller.eks.aws.dev/][ghp].
16 |
17 | ### Concepts
18 |
19 | To get started, please read through [API concepts][concepts]. These documents give the necessary background to understand the API and the use-cases it targets.
20 |
21 | ### Getting started
22 |
23 | Once you have a good understanding of the API at a higher-level, check out
24 | [getting started][getting-started] to install your first Gateway controller and try out
25 | one of the guides.
26 |
27 | ### References
28 |
29 | A complete API reference, please refer to:
30 |
31 | - [API reference][spec]
32 | - [Go docs for the package][godoc]
33 |
34 | ## Contributing
35 |
36 | Developer guide can be found on the [developer guide page][dev].
37 | Our Kubernetes Slack channel is [#aws-gateway-api-controller][slack].
38 |
39 | ### Code of conduct
40 |
41 | Participation in the Kubernetes community is governed by the
42 | [Kubernetes Code of Conduct](code-of-conduct.md).
43 |
44 | ## Security
45 |
46 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
47 |
48 | ## License
49 |
50 | This project is licensed under the Apache-2.0 License.
51 |
52 | [ghp]: https://www.gateway-api-controller.eks.aws.dev/
53 | [dev]: https://www.gateway-api-controller.eks.aws.dev/contributing/developer/
54 | [slack]: https://kubernetes.slack.com/messages/aws-gateway-api-controller
55 | [getting-started]: https://www.gateway-api-controller.eks.aws.dev/guides/getstarted/
56 | [spec]: https://www.gateway-api-controller.eks.aws.dev/api-reference/
57 | [concepts]: https://www.gateway-api-controller.eks.aws.dev/concepts/
58 | [gh_release]: https://github.com/aws/aws-application-networking-k8s/releases/tag/v1.1.0
59 | [godoc]: https://www.gateway-api-controller.eks.aws.dev/
60 |
--------------------------------------------------------------------------------
/code-of-conduct.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 | The AWS Gateway API Controller project follows the [CNCF Community Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
3 |
--------------------------------------------------------------------------------
/config/crds/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - bases/gateway.networking.k8s.io_tlsroutes.yaml
5 | - bases/application-networking.k8s.aws_serviceexports.yaml
6 | - bases/application-networking.k8s.aws_serviceimports.yaml
7 | - bases/application-networking.k8s.aws_targetgrouppolicies.yaml
8 | - bases/application-networking.k8s.aws_vpcassociationpolicies.yaml
9 | - bases/application-networking.k8s.aws_accesslogpolicies.yaml
10 | - bases/application-networking.k8s.aws_iamauthpolicies.yaml
11 |
--------------------------------------------------------------------------------
/config/default/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - ../crds
5 | - ../rbac
6 | - ../manager
7 | - ../webhook
8 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
9 | #- ../prometheus
10 |
11 | patchesStrategicMerge:
12 | # Protect the /metrics endpoint by putting it behind auth.
13 | # If you want your controller-manager to expose the /metrics
14 | # endpoint w/o any authn/z, please comment the following line.
15 | - manager_auth_proxy_patch.yaml
16 |
17 | # Mount the controller config file for loading manager configurations
18 | # through a ComponentConfig type
19 | #- manager_config_patch.yaml
20 |
--------------------------------------------------------------------------------
/config/default/manager_auth_proxy_patch.yaml:
--------------------------------------------------------------------------------
1 | # This patch inject a sidecar container which is a HTTP proxy for the
2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
3 | apiVersion: apps/v1
4 | kind: Deployment
5 | metadata:
6 | name: gateway-api-controller
7 | namespace: aws-application-networking-system
8 | spec:
9 | template:
10 | spec:
11 | containers:
12 | - name: kube-rbac-proxy
13 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
14 | args:
15 | - "--secure-listen-address=0.0.0.0:8443"
16 | - "--upstream=http://127.0.0.1:8080/"
17 | - "--logtostderr=true"
18 | - "--v=10"
19 | ports:
20 | - containerPort: 8443
21 | protocol: TCP
22 | name: https
23 | - name: manager
24 | args:
25 | - "--health-probe-bind-address=:8081"
26 | - "--metrics-bind-address=0.0.0.0:8080"
27 | - "--leader-elect"
28 |
--------------------------------------------------------------------------------
/config/default/manager_config_patch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: gateway-api-controller
5 | namespace: aws-application-networking-system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: manager
11 | args:
12 | - "--config=controller_manager_config.yaml"
13 | volumeMounts:
14 | - name: manager-config
15 | mountPath: /controller_manager_config.yaml
16 | subPath: controller_manager_config.yaml
17 | volumes:
18 | - name: manager-config
19 | configMap:
20 | name: manager-config
21 |
--------------------------------------------------------------------------------
/config/iam/recommended-inline-policy.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": [
7 | "vpc-lattice:*",
8 | "ec2:DescribeVpcs",
9 | "ec2:DescribeSubnets",
10 | "ec2:DescribeTags",
11 | "ec2:DescribeSecurityGroups",
12 | "logs:CreateLogDelivery",
13 | "logs:GetLogDelivery",
14 | "logs:DescribeLogGroups",
15 | "logs:PutResourcePolicy",
16 | "logs:DescribeResourcePolicies",
17 | "logs:UpdateLogDelivery",
18 | "logs:DeleteLogDelivery",
19 | "logs:ListLogDeliveries",
20 | "tag:GetResources",
21 | "firehose:TagDeliveryStream",
22 | "s3:GetBucketPolicy",
23 | "s3:PutBucketPolicy"
24 | ],
25 | "Resource": "*"
26 | },
27 | {
28 | "Effect" : "Allow",
29 | "Action" : "iam:CreateServiceLinkedRole",
30 | "Resource" : "arn:aws:iam::*:role/aws-service-role/vpc-lattice.amazonaws.com/AWSServiceRoleForVpcLattice",
31 | "Condition" : {
32 | "StringLike" : {
33 | "iam:AWSServiceName" : "vpc-lattice.amazonaws.com"
34 | }
35 | }
36 | },
37 | {
38 | "Effect" : "Allow",
39 | "Action" : "iam:CreateServiceLinkedRole",
40 | "Resource" : "arn:aws:iam::*:role/aws-service-role/delivery.logs.amazonaws.com/AWSServiceRoleForLogDelivery",
41 | "Condition" : {
42 | "StringLike" : {
43 | "iam:AWSServiceName" : "delivery.logs.amazonaws.com"
44 | }
45 | }
46 | }
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/config/manager/controller_manager_config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
2 | kind: ControllerManagerConfig
3 | health:
4 | healthProbeBindAddress: :8081
5 | metrics:
6 | bindAddress: 127.0.0.1:8080
7 | webhook:
8 | port: 9443
9 | leaderElection:
10 | leaderElect: true
11 | resourceName: 6288bc47.amazon-vpc-lattice.io
12 |
--------------------------------------------------------------------------------
/config/manager/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - manager.yaml
5 |
6 | generatorOptions:
7 | disableNameSuffixHash: true
8 |
9 | configMapGenerator:
10 | - files:
11 | - controller_manager_config.yaml
12 | name: manager-config
13 | images:
14 | - name: controller
15 | newName: public.ecr.aws/aws-application-networking-k8s/aws-gateway-controller
16 | newTag: v1.1.1
17 |
--------------------------------------------------------------------------------
/config/overlays/namespaced/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - ../../default
3 | patches:
4 | - path: role.json
5 | target:
6 | group: rbac.authorization.k8s.io
7 | version: v1
8 | kind: ClusterRole
9 | name: aws-application-networking-controller
10 | - path: role-binding.json
11 | target:
12 | group: rbac.authorization.k8s.io
13 | version: v1
14 | kind: ClusterRoleBinding
15 | name: aws-application-networking-controller
16 |
--------------------------------------------------------------------------------
/config/overlays/namespaced/role-binding.json:
--------------------------------------------------------------------------------
1 | [{"op": "replace", "path": "/kind", "value": "RoleBinding"},
2 | {"op": "add", "path": "/metadata/namespace", "value": "aws-application-networking-system"},
3 | {"op": "replace", "path": "/roleRef/kind", "value": "Role"}]
4 |
--------------------------------------------------------------------------------
/config/overlays/namespaced/role.json:
--------------------------------------------------------------------------------
1 | [{"op": "replace", "path": "/kind", "value": "Role"},
2 | {"op": "add", "path": "/metadata/namespace", "value": "aws-application-networking-system"}]
3 |
--------------------------------------------------------------------------------
/config/prometheus/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - monitor.yaml
5 |
--------------------------------------------------------------------------------
/config/prometheus/monitor.yaml:
--------------------------------------------------------------------------------
1 |
2 | # Prometheus Monitor Service (Metrics)
3 | apiVersion: monitoring.coreos.com/v1
4 | kind: ServiceMonitor
5 | metadata:
6 | labels:
7 | control-plane: gateway-api-controller
8 | name: gateway-api-controller-metrics-monitor
9 | namespace: aws-application-networking-system
10 | spec:
11 | endpoints:
12 | - path: /metrics
13 | port: https
14 | scheme: https
15 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
16 | tlsConfig:
17 | insecureSkipVerify: true
18 | selector:
19 | matchLabels:
20 | control-plane: gateway-api-controller
21 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_client_clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: metrics-reader
5 | rules:
6 | - nonResourceURLs:
7 | - "/metrics"
8 | verbs:
9 | - get
10 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: proxy-role
5 | rules:
6 | - apiGroups:
7 | - authentication.k8s.io
8 | resources:
9 | - tokenreviews
10 | verbs:
11 | - create
12 | - apiGroups:
13 | - authorization.k8s.io
14 | resources:
15 | - subjectaccessreviews
16 | verbs:
17 | - create
18 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_role_binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: proxy-rolebinding
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: ClusterRole
8 | name: proxy-role
9 | subjects:
10 | - kind: ServiceAccount
11 | name: gateway-api-controller
12 | namespace: aws-application-networking-system
13 |
--------------------------------------------------------------------------------
/config/rbac/auth_proxy_service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | control-plane: gateway-api-controller
6 | name: gateway-api-controller-metrics-service
7 | namespace: aws-application-networking-system
8 | spec:
9 | ports:
10 | - name: https
11 | port: 8443
12 | protocol: TCP
13 | targetPort: https
14 | selector:
15 | control-plane: gateway-api-controller
16 |
--------------------------------------------------------------------------------
/config/rbac/cluster-role-binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: aws-application-networking-controller
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: ClusterRole
8 | name: aws-application-networking-controller
9 | subjects:
10 | - kind: ServiceAccount
11 | name: gateway-api-controller
12 | namespace: aws-application-networking-system
13 |
--------------------------------------------------------------------------------
/config/rbac/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | # All RBAC will be applied under this service account in
5 | # the deployment namespace. You may comment out this resource
6 | # if your manager will use a service account that exists at
7 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding
8 | # subjects if changing service account names.
9 | - cluster-role-controller.yaml
10 | - cluster-role-binding.yaml
11 | - service-account.yaml
12 | # Comment the following 4 lines if you want to disable
13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy)
14 | # which protects your /metrics endpoint.
15 | - auth_proxy_service.yaml
16 | - auth_proxy_role.yaml
17 | - auth_proxy_role_binding.yaml
18 | - auth_proxy_client_clusterrole.yaml
19 |
--------------------------------------------------------------------------------
/config/rbac/service-account.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: gateway-api-controller
5 | namespace: aws-application-networking-system
6 |
--------------------------------------------------------------------------------
/config/webhook/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - manifests.yaml
--------------------------------------------------------------------------------
/config/webhook/manifests.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: admissionregistration.k8s.io/v1
3 | kind: MutatingWebhookConfiguration
4 | metadata:
5 | name: aws-appnet-gwc-mutating-webhook
6 | webhooks:
7 | - admissionReviewVersions:
8 | - v1
9 | clientConfig:
10 | service:
11 | name: webhook-service
12 | namespace: aws-application-networking-system
13 | path: /mutate-pod
14 | failurePolicy: Fail
15 | name: mpod.gwc.k8s.aws
16 | rules:
17 | - apiGroups:
18 | - ""
19 | apiVersions:
20 | - v1
21 | operations:
22 | - CREATE
23 | resources:
24 | - pods
25 | sideEffects: None
26 | namespaceSelector:
27 | matchExpressions:
28 | - key: application-networking.k8s.aws/pod-readiness-gate-inject
29 | operator: In
30 | values:
31 | - enabled
32 | objectSelector:
33 | matchExpressions:
34 | - key: app.kubernetes.io/name
35 | operator: NotIn
36 | values:
37 | - gateway-api-controller
38 | ---
39 | apiVersion: v1
40 | kind: Service
41 | metadata:
42 | name: webhook-service
43 | namespace: aws-application-networking-system
44 | spec:
45 | ports:
46 | - port: 443
47 | targetPort: 9443
48 | selector:
49 | control-plane: gateway-api-controller
--------------------------------------------------------------------------------
/docgen/.gitignore:
--------------------------------------------------------------------------------
1 | docs.html
2 | api-reference.md
--------------------------------------------------------------------------------
/docgen/README.md:
--------------------------------------------------------------------------------
1 | # Generate API Docs
2 |
3 | Install doc generator
4 |
5 | ```sh
6 | go install github.com/ahmetb/gen-crd-api-reference-docs@v0.3.0
7 | ```
8 |
9 | Generate html docs
10 |
11 | ``` sh
12 | cd docgen
13 |
14 | gen-crd-api-reference-docs -config config.json -api-dir "../pkg/apis/applicationnetworking/v1alpha1/" -out-file docs.html
15 | ```
16 |
17 | Add generated content to template
18 |
19 | ``` sh
20 | cat api-reference-base.md docs.html > ../docs/api-reference.md
21 | ```
22 |
--------------------------------------------------------------------------------
/docgen/api-reference-base.md:
--------------------------------------------------------------------------------
1 | # API Reference
2 |
3 | This page contains the API specification for Custom Resource Definitions supported by the Application Networking K8s Controller.
4 |
5 |
--------------------------------------------------------------------------------
/docgen/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "hideMemberFields": [
3 | "TypeMeta"
4 | ],
5 | "hideTypePatterns": [
6 | "ParseError$",
7 | "List$"
8 | ],
9 | "externalPackages": [
10 | {
11 | "typeMatchPrefix": "^sigs\\.k8s\\.io/gateway-api/apis/v1alpha2\\.PolicyTargetReference",
12 | "docsURLTemplate": "https://gateway-api.sigs.k8s.io/geps/gep-713/?h=policytargetreference#policy-targetref-api"
13 | },
14 | {
15 | "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Duration$",
16 | "docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"
17 | },
18 | {
19 | "typeMatchPrefix": "^k8s\\.io/(api|apimachinery/pkg/apis)/",
20 | "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}"
21 | },
22 | {
23 | "typeMatchPrefix": "^github\\.com/knative/pkg/apis/duck/",
24 | "docsURLTemplate": "https://pkg.go.dev/github.com/knative/pkg/apis/duck/{{arrIndex .PackageSegments -1}}#{{.TypeIdentifier}}"
25 | }
26 | ],
27 | "typeDisplayNamePrefixOverrides": {
28 | "k8s.io/api/": "Kubernetes ",
29 | "k8s.io/apimachinery/pkg/apis/": "Kubernetes "
30 | },
31 | "markdownDisabled": false
32 | }
33 |
--------------------------------------------------------------------------------
/docgen/template/members.tpl:
--------------------------------------------------------------------------------
1 | {{ define "members" }}
2 |
3 | {{ range .Members }}
4 | {{ if not (hiddenMember .)}}
5 |
6 |
7 | {{ fieldName . }}
8 |
9 | {{ if linkForType .Type }}
10 |
11 | {{ typeDisplayName .Type }}
12 |
13 | {{ else }}
14 | {{ typeDisplayName .Type }}
15 | {{ end }}
16 |
17 | |
18 |
19 | {{ if fieldEmbedded . }}
20 |
21 | (Members of {{ fieldName . }} are embedded into this type.)
22 |
23 | {{ end}}
24 |
25 | {{ if isOptionalMember .}}
26 | (Optional)
27 | {{ end }}
28 |
29 | {{ safe (renderComments .CommentLines) }}
30 |
31 | {{ if and (eq (.Type.Name.Name) "ObjectMeta") }}
32 | Refer to the Kubernetes API documentation for the fields of the
33 | metadata field.
34 | {{ end }}
35 |
36 | {{ if or (eq (fieldName .) "spec") }}
37 |
38 |
39 |
40 | {{ template "members" .Type }}
41 |
42 | {{ end }}
43 | |
44 |
45 | {{ end }}
46 | {{ end }}
47 |
48 | {{ end }}
49 |
--------------------------------------------------------------------------------
/docgen/template/pkg.tpl:
--------------------------------------------------------------------------------
1 | {{ define "packages" }}
2 |
3 | {{ with .packages}}
4 | Packages:
5 |
12 | {{ end}}
13 |
14 | {{ range .packages }}
15 |
16 | {{- packageDisplayName . -}}
17 |
18 |
19 | {{ with (index .GoPackages 0 )}}
20 | {{ with .DocComments }}
21 |
22 | {{ safe (renderComments .) }}
23 |
24 | {{ end }}
25 | {{ end }}
26 |
27 | Resource Types:
28 |
29 | {{- range (visibleTypes (sortedTypes .Types)) -}}
30 | {{ if isExportedType . -}}
31 | -
32 | {{ typeDisplayName . }}
33 |
34 | {{- end }}
35 | {{- end -}}
36 |
37 |
38 | {{ range (visibleTypes (sortedTypes .Types))}}
39 | {{ template "type" . }}
40 | {{ end }}
41 |
42 | {{ end }}
43 |
44 |
45 | Generated with gen-crd-api-reference-docs
46 | {{ with .gitCommit }} on git commit {{ . }}
{{end}}.
47 |
48 |
49 | {{ end }}
50 |
--------------------------------------------------------------------------------
/docgen/template/placeholder.go:
--------------------------------------------------------------------------------
1 | // Placeholder file to make Go vendor this directory properly.
2 | package template
3 |
--------------------------------------------------------------------------------
/docgen/template/type.tpl:
--------------------------------------------------------------------------------
1 | {{ define "type" }}
2 |
3 |
4 | {{- .Name.Name }}
5 | {{ if eq .Kind "Alias" }}({{.Underlying}}
alias){{ end -}}
6 |
7 | {{ with (typeReferences .) }}
8 |
9 | (Appears on:
10 | {{- $prev := "" -}}
11 | {{- range . -}}
12 | {{- if $prev -}}, {{ end -}}
13 | {{- $prev = . -}}
14 | {{ typeDisplayName . }}
15 | {{- end -}}
16 | )
17 |
18 | {{ end }}
19 |
20 |
21 | {{ safe (renderComments .CommentLines) }}
22 |
23 |
24 | {{ with (constantsOfType .) }}
25 |
26 |
27 |
28 | Value |
29 | Description |
30 |
31 |
32 |
33 | {{- range . -}}
34 |
35 | {{- /*
36 | renderComments implicitly creates a element, so we
37 | add one to the display name as well to make the contents
38 | of the two cells align evenly.
39 | */ -}}
40 |
{{ typeDisplayName . }} |
41 | {{ safe (renderComments .CommentLines) }} |
42 |
43 | {{- end -}}
44 |
45 |
46 | {{ end }}
47 |
48 | {{ if .Members }}
49 |
50 |
51 |
52 | Field |
53 | Description |
54 |
55 |
56 |
57 | {{ if isExportedType . }}
58 |
59 |
60 | apiVersion
61 | string |
62 |
63 |
64 | {{apiGroup .}}
65 |
66 | |
67 |
68 |
69 |
70 | kind
71 | string
72 | |
73 | {{.Name.Name}} |
74 |
75 | {{ end }}
76 | {{ template "members" .}}
77 |
78 |
79 | {{ end }}
80 |
81 | {{ end }}
82 |
--------------------------------------------------------------------------------
/docs/api-types/service-export.md:
--------------------------------------------------------------------------------
1 | # ServiceExport API Reference
2 |
3 | ## Introduction
4 |
5 | In AWS Gateway API Controller, `ServiceExport` enables a Service for multi-cluster traffic setup.
6 | Clusters can import the exported service with [`ServiceImport`](service-import.md) resource.
7 |
8 | Internally, creating a ServiceExport creates a standalone VPC Lattice [target group](https://docs.aws.amazon.com/vpc-lattice/latest/ug/target-groups.html).
9 | Even without ServiceImports, creating ServiceExports can be useful in case you only need the target groups created;
10 | for example, using target groups in the VPC Lattice setup outside Kubernetes.
11 |
12 | Note that ServiceExport is not the implementation of Kubernetes [Multicluster Service APIs](https://multicluster.sigs.k8s.io/concepts/multicluster-services-api/);
13 | instead AWS Gateway API Controller uses its own version of the resource for the purpose of Gateway API integration.
14 |
15 |
16 | ### Limitations
17 | * The exported Service can only be used in HTTPRoutes. GRPCRoute is currently not supported.
18 | * Limited to one ServiceExport per Service. If you need multiple exports representing each port,
19 | you should create multiple Service-ServiceExport pairs.
20 |
21 | ### Annotations
22 |
23 | * `application-networking.k8s.aws/port`
24 | Represents which port of the exported Service will be used.
25 | When a comma-separated list of ports is provided, the traffic will be distributed to all ports in the list.
26 |
27 | ## Example Configuration
28 |
29 | The following yaml will create a ServiceExport for a Service named `service-1`:
30 | ```yaml
31 | apiVersion: application-networking.k8s.aws/v1alpha1
32 | kind: ServiceExport
33 | metadata:
34 | name: service-1
35 | annotations:
36 | application-networking.k8s.aws/port: "9200"
37 | spec: {}
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/api-types/service-import.md:
--------------------------------------------------------------------------------
1 | # ServiceImport API Reference
2 |
3 | ## Introduction
4 |
5 | `ServiceImport` is a resource referring to a Service outside the cluster, paired with [`ServiceExport`](service-export.md)
6 | resource defined in the other clusters.
7 |
8 | Just like Services, ServiceImports can be a backend reference of HTTPRoutes. Along with the cluster's own Services
9 | (and ServiceImports from even more clusters), you can distribute the traffic across multiple VPCs and clusters.
10 |
11 | Note that ServiceImport is not the implementation of Kubernetes [Multicluster Service APIs](https://multicluster.sigs.k8s.io/concepts/multicluster-services-api/);
12 | instead AWS Gateway API Controller uses its own version of the resource for the purpose of Gateway API integration.
13 |
14 |
15 | ### Limitations
16 | * ServiceImport shares the limitations of [ServiceExport](service-export.md).
17 | * The controller only supports ServiceImport through HTTPRoute; sending traffic directly is not supported.
18 | * BackendRef ports pointing to ServiceImport is not respected. Use [port annotation](service-export.md#annotations) of ServiceExport instead.
19 |
20 | ### Annotations
21 | * `application-networking.k8s.aws/aws-eks-cluster-name`
22 | (Optional) When specified, the controller will only find target groups exported from the cluster.
23 | * `application-networking.k8s.aws/aws-vpc`
24 | (Optional) When specified, the controller will only find target groups exported from the cluster with the provided VPC ID.
25 |
26 | ## Example Configuration
27 |
28 | The following yaml imports `service-1` exported from the designated cluster.
29 | ```yaml
30 | apiVersion: application-networking.k8s.aws/v1alpha1
31 | kind: ServiceImport
32 | metadata:
33 | name: service-1
34 | annotations:
35 | application-networking.k8s.aws/aws-eks-cluster-name: "service-1-owner-cluster"
36 | application-networking.k8s.aws/aws-vpc: "service-1-owner-vpc-id"
37 | spec: {}
38 | ```
39 |
40 | The following example HTTPRoute directs traffic to the above ServiceImport.
41 | ```yaml
42 | apiVersion: gateway.networking.k8s.io/v1
43 | kind: HTTPRoute
44 | metadata:
45 | name: my-route
46 | spec:
47 | parentRefs:
48 | - name: my-gateway
49 | sectionName: http
50 | rules:
51 | - backendRefs:
52 | - name: service-1
53 | kind: ServiceImport
54 | ```
--------------------------------------------------------------------------------
/docs/api-types/service.md:
--------------------------------------------------------------------------------
1 | # Service API Reference
2 |
3 | ## Introduction
4 |
5 | Kubernetes Services define a logical set of Pods and a policy by which to access them, often referred to as a
6 | microservice. The set of Pods targeted by a Service is determined by a `selector`.
7 |
8 | ### Service Key Features & Limitations
9 |
10 | **Features**:
11 |
12 | - **Load Balancing**: Services offer load balancing, distributing network traffic across the Pods.
13 | - **Service Types**: Supports different types, such as ClusterIP (default), NodePort, LoadBalancer, and ExternalName.
14 | - **Stable IP Address**: Each Service has a stable IP address, even when the Pods it routes to change.
15 |
16 | **Limitations**:
17 |
18 | - **Immutable Selector**: Once a Service is created, its `selector` and `type` fields cannot be updated.
19 | - **Single Namespace**: Services can only route to Pods within the same namespace.
20 | - **ExternalName Limitation**: `ExternalName` type is not supported by this controller.
21 |
22 | ## Example Configuration:
23 |
24 | ### Example 1
25 |
26 | Here's a basic example of a Service that routes traffic to Pods with the label `app=MyApp`:
27 |
28 | ```yaml
29 | apiVersion: v1
30 | kind: Service
31 | metadata:
32 | name: my-service
33 | spec:
34 | selector:
35 | app: MyApp
36 | ports:
37 | - protocol: TCP
38 | port: 80
39 | targetPort: 8080
40 | ```
41 |
42 | In this example:
43 |
44 | - The Service is named `my-service`.
45 | - It targets Pods with the label `app=MyApp`.
46 | - The Service exposes port 80, which routes to target port 8080 on the Pods.
47 |
48 | ---
49 |
50 | This `Service` documentation provides an overview of its key features, limitations, and basic examples of configuration
51 | within Kubernetes. For detailed specifications and advanced configurations, refer to the official
52 | [Kubernetes Service documentation](https://kubernetes.io/docs/concepts/services-networking/service/).
53 |
--------------------------------------------------------------------------------
/docs/api-types/tls-route.md:
--------------------------------------------------------------------------------
1 | # TLSRoute API Reference
2 |
3 | ## Introduction
4 |
5 | With integration of the Gateway API, AWS Gateway API Controller supports `TLSRoute`.
6 | This allows you to define and manage end-to-end TLS encrypted traffic routing to your Kubernetes clusters.
7 |
8 | ### Considerations
9 |
10 | - `TLSRoute` sectionName must refer to a `TLS` protocol listener with `mode: Passthrough` in the parentRefs `Gateway`.
11 | - `TLSRoute` only supports to have one rule.
12 | - `TLSRoute` does not support any rule matching condition.
13 | - The `hostnames` field with exactly one host name is required.
14 |
15 |
16 | ## Example Configuration
17 |
18 | Here is a sample configuration that demonstrates how to set up a `TLSRoute` resource to route end-to-end TLS encrypted traffic to a nginx service:
19 |
20 | ```yaml
21 | apiVersion: gateway.networking.k8s.io/v1alpha2
22 | kind: TLSRoute
23 | metadata:
24 | name: nginx-tls-route
25 | spec:
26 | hostnames:
27 | - nginx-test.my-test.com
28 | parentRefs:
29 | - name: my-hotel-tls-passthrough
30 | sectionName: tls
31 | rules:
32 | - backendRefs:
33 | - name: nginx-tls
34 | kind: Service
35 | port: 443
36 | ```
37 |
38 | In this example:
39 |
40 | - The `TLSRoute` is named ` nginx-tls-route` and is associated with a parent gateway named `my-hotel-tls-passthrough` that has
41 | a listener section named `tls`:
42 | ```
43 | - name: tls
44 | protocol: TLS
45 | port: 443
46 | tls:
47 | mode: Passthrough
48 | ```
49 | - The `TLSRoute` is configured to route traffic to a k8s service named `nginx-tls` on port 443.
50 | - The `hostnames` field is set to `nginx-test.my-test.com`. The customer must use this hostname to send traffic to the nginx service.
51 |
52 |
53 | For the detailed tls passthrough traffic connectivity setup, please refer the user guide [here](../guides/tls-passthrough.md).
54 |
55 | For the detailed Gateway API `TLSRoute` resource specifications, you can refer to the
56 | Kubernetes official [documentation](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1alpha2.TLSRoute).
57 |
58 | For the VPC Lattice tls passthrough Listener configuration details, you can refer to the VPC Lattice [documentation](https://docs.aws.amazon.com/vpc-lattice/latest/ug/tls-listeners.html).
--------------------------------------------------------------------------------
/docs/concepts/concepts.md:
--------------------------------------------------------------------------------
1 | # AWS Gateway API Controller User Guide
2 |
3 | As part of the VPC Lattice launch, AWS introduced the AWS Gateway API Controller ; an implementation of the Kubernetes Gateway API. Gateway API is an open-source standard interface to enable Kubernetes application networking through expressive, extensible, and role-oriented interfaces. AWS Gateway API controller extends custom resources, defined by Gateway API, which allows you to create VPC Lattice resources using Kubernetes APIs.
4 |
5 | When installed in your cluster, the controller watches for the creation of Gateway API resources such as gateways and routes and provisions corresponding Amazon VPC Lattice objects. This enables users to configure VPC Lattice Services, VPC Lattice service networks and Target Groups using Kubernetes APIs, without needing to write custom code or manage sidecar proxies. The AWS Gateway API Controller is an open-source project and fully supported by Amazon.
6 |
7 | AWS Gateway API Controller integrates with Amazon VPC Lattice and allows you to:
8 |
9 | * Handle network connectivity seamlessly between services across VPCs and accounts.
10 | * Discover VPC Lattice services spanning multiple Kubernetes clusters.
11 | * Implement a defense-in-depth strategy to secure communication between those services.
12 | * Observe the request/response traffic across the services.
13 |
14 | This documentation describes how to set up the AWS Gateway API Controller, provides example use cases, development concepts, and API references. AWS Gateway API Controller will provide developers the ability to publish services running on Kubernetes cluster and other compute platforms on AWS such as AWS Lambda or Amazon EC2. Once the AWS Gateway API controller deployed and running, you will be able to manage services for multiple Kubernetes clusters and other compute targets on AWS through the following:
15 |
16 | * **CLI**: Use `aws` and `eksctl` to create clusters and set up AWS policies. Then use `kubectl` and YAML files to set up Kubernetes objects.
17 | * **AWS Console**: View VPC Lattice assets through the VPC area of the AWS console.
18 |
19 | Integrating with the Kubernetes Gateway API provides a kubernetes-native experience for developers to create services, manage network routing and traffic behaviour without the heavy lifting managing the underlying networking infrastrcuture. This lets you work with Kubernetes service-related resources using Kubernetes APIs and custom resource definitions (CRDs) defined by the Kubernetes [networking.k8s.io specification](https://gateway-api.sigs.k8s.io/references/spec/).
20 |
21 | For more information on this technology, see [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/).
--------------------------------------------------------------------------------
/docs/faq.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions (FAQ)
2 |
3 |
4 |
5 | **How can I get involved with AWS Gateway API Controller?**
6 |
7 | We welcome general feedback, questions, feature requests, or bug reports by creating a [Github issue](https://github.com/aws/aws-application-networking-k8s/issues/new).
8 |
9 | **Where can I find AWS Gateway API Controller releases?**
10 |
11 | AWS Gateway API Controller releases are tags of the Github repository. The [Github releases page](https://github.com/aws/aws-application-networking-k8s/releases) shows all the releases.
12 |
13 | **Which EKS CNI versions are supported?**
14 |
15 | Your AWS VPC CNI must be v1.8.0 or later to work with VPC Lattice.
16 |
17 | **Which versions of Gateway API are supported?**
18 |
19 | AWS Gateway API Controller supports Gateway API CRD bundle versions `v1.1` or greater. Not all features of Gateway API are supported - for detailed features and limitation, please refer to individual API references. Please note that users are required to install Gateway API CRDs themselves as these are no longer bundled as of release `v1.1.0`. The latest Gateway API CRDs are available [here](https://gateway-api.sigs.k8s.io/). Please [follow this installation](https://gateway-api.sigs.k8s.io/guides/#installing-gateway-api) process.
--------------------------------------------------------------------------------
/docs/guides/upgrading-v1-0-x-to-v1-1-y.md:
--------------------------------------------------------------------------------
1 | # Update the AWS Gateway API Controller from v1.0.x to v1.1.y
2 |
3 | Release `v1.1.0` of the AWS Gateway API Controller is built against `v1.2` of the Gateway API spec, but the controller is also compatible with the `v1.1` Gateway API. It is _not_ compatible the `v1.0` Gateway API.
4 |
5 | Previous `v1.0.x` builds of the controller were built against `v1.0` of the Gateway API spec. This guide outlines the controller upgrade process from `v1.0.x` to `v1.1.y`. Please note that users are required to install Gateway API CRDs themselves as these are no longer bundled as of release `v1.1.0`. The latest Gateway API CRDs are available [here](https://gateway-api.sigs.k8s.io/). Please [follow this installation](https://gateway-api.sigs.k8s.io/guides/#installing-gateway-api) process.
6 |
7 | # Basic Upgrade Process
8 |
9 | 1. Back up configuration, in particular GRPCRoute objects
10 | 2. Disable `v1.0.x` controller (e.g. scale to zero)
11 | 3. Update Gateway API CRDs to `v1.1.0`, available [here](https://gateway-api.sigs.k8s.io/)
12 | 4. Deploy and launch `v1.1.y` controller version
13 |
14 | With the basic upgrade process, previously created GRPCRoutes on `v1alpha2` will automatically update to `v1` once they are reconciled by the controller. Alternatively, you can manually update your GRPCRoute versions (for example export to YAML, update version number, and apply updates). Creation of new GRPCRoutes objects using `v1alpha2` will be rejected.
15 |
16 | # Upgrading to Gateway API `v1.2`
17 |
18 | Moving to GatewayAPI `v1.2` can require an additional step as `v1alpha2` GRPCRoute objects have been removed. If GRPCRoute objects are not already on `v1`, you will need to follow steps outlined in the `v1.2.0` [release notes](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.0).
19 |
20 | 1. Back up configuration, in particular GRPCRoute objects
21 | 2. Disable `v1.0.x` controller (e.g. scale to zero)
22 | 3. Update Gateway API CRDs to `v1.1.0`, available [here](https://gateway-api.sigs.k8s.io/)
23 | 4. Deploy and launch `v1.1.Y` controller version
24 | 5. Take upgrade steps outlined in `v1.2.0` [Gateway API release notes](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.0)
25 | 6. Update Gateway API CRDs to `v1.2.0`
--------------------------------------------------------------------------------
/docs/images/GatewayUserGuideFigures.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/GatewayUserGuideFigures.pptx
--------------------------------------------------------------------------------
/docs/images/accept-resource-share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/accept-resource-share.png
--------------------------------------------------------------------------------
/docs/images/controller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/controller.png
--------------------------------------------------------------------------------
/docs/images/example1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/example1.png
--------------------------------------------------------------------------------
/docs/images/example2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/example2.png
--------------------------------------------------------------------------------
/docs/images/fundamentals-mapping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/fundamentals-mapping.png
--------------------------------------------------------------------------------
/docs/images/multi-cluster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/multi-cluster.png
--------------------------------------------------------------------------------
/docs/images/personae.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/personae.png
--------------------------------------------------------------------------------
/docs/images/resource-share1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share1.png
--------------------------------------------------------------------------------
/docs/images/resource-share2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share2.png
--------------------------------------------------------------------------------
/docs/images/resource-share3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share3.png
--------------------------------------------------------------------------------
/docs/images/resource-share4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share4.png
--------------------------------------------------------------------------------
/docs/images/resource-share5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share5.png
--------------------------------------------------------------------------------
/docs/images/resource-share6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/resource-share6.png
--------------------------------------------------------------------------------
/docs/images/service-network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/service-network.png
--------------------------------------------------------------------------------
/docs/images/service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/service.png
--------------------------------------------------------------------------------
/docs/images/serviceimport.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/serviceimport.png
--------------------------------------------------------------------------------
/docs/images/tlsroute-multi-cluster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/aws-application-networking-k8s/84fcfae52776d9b84e1cdcc9b792c64e9907e9b7/docs/images/tlsroute-multi-cluster.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: AWS Gateway API Controller User Guide
3 | template: home.html
4 | exclude_search: true
5 | ---
6 |
--------------------------------------------------------------------------------
/files/controller-installation/deploy-namesystem.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | labels:
5 | control-plane: gateway-api-controller
6 | name: aws-application-networking-system
7 |
--------------------------------------------------------------------------------
/files/controller-installation/gatewayclass.yaml:
--------------------------------------------------------------------------------
1 | # Create a new Gateway Class for AWS VPC lattice provider
2 | apiVersion: gateway.networking.k8s.io/v1beta1
3 | kind: GatewayClass
4 | metadata:
5 | name: amazon-vpc-lattice
6 | spec:
7 | controllerName: application-networking.k8s.aws/gateway-api-controller
8 |
--------------------------------------------------------------------------------
/files/controller-installation/recommended-inline-policy.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": [
7 | "vpc-lattice:*",
8 | "ec2:DescribeVpcs",
9 | "ec2:DescribeSubnets",
10 | "ec2:DescribeTags",
11 | "ec2:DescribeSecurityGroups",
12 | "logs:CreateLogDelivery",
13 | "logs:GetLogDelivery",
14 | "logs:DescribeLogGroups",
15 | "logs:PutResourcePolicy",
16 | "logs:DescribeResourcePolicies",
17 | "logs:UpdateLogDelivery",
18 | "logs:DeleteLogDelivery",
19 | "logs:ListLogDeliveries",
20 | "tag:GetResources",
21 | "firehose:TagDeliveryStream",
22 | "s3:GetBucketPolicy",
23 | "s3:PutBucketPolicy"
24 | ],
25 | "Resource": "*"
26 | },
27 | {
28 | "Effect" : "Allow",
29 | "Action" : "iam:CreateServiceLinkedRole",
30 | "Resource" : "arn:aws:iam::*:role/aws-service-role/vpc-lattice.amazonaws.com/AWSServiceRoleForVpcLattice",
31 | "Condition" : {
32 | "StringLike" : {
33 | "iam:AWSServiceName" : "vpc-lattice.amazonaws.com"
34 | }
35 | }
36 | },
37 | {
38 | "Effect" : "Allow",
39 | "Action" : "iam:CreateServiceLinkedRole",
40 | "Resource" : "arn:aws:iam::*:role/aws-service-role/delivery.logs.amazonaws.com/AWSServiceRoleForLogDelivery",
41 | "Condition" : {
42 | "StringLike" : {
43 | "iam:AWSServiceName" : "delivery.logs.amazonaws.com"
44 | }
45 | }
46 | }
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/files/examples/greeter-grpc-route.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: GRPCRoute
3 | metadata:
4 | name: greeter-grpc-route
5 | spec:
6 | parentRefs:
7 | - name: my-hotel
8 | sectionName: https
9 | rules:
10 | - backendRefs:
11 | - name: greeter-grpc-server
12 | kind: Service
13 | port: 443
14 | weight: 10
15 | matches:
16 | - method:
17 | service: helloworld.Greeter
18 | method: SayHello
19 |
--------------------------------------------------------------------------------
/files/examples/greeter-grpc-server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: greeter-grpc-server
5 | labels:
6 | app: greeter-grpc-server
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: greeter-grpc-server
12 | template:
13 | metadata:
14 | labels:
15 | app: greeter-grpc-server
16 | spec:
17 | containers:
18 | - name: greeter-grpc-server
19 | image: aguilbau/hello-world-grpc:latest
20 |
21 |
22 | ---
23 | apiVersion: v1
24 | kind: Service
25 | metadata:
26 | name: greeter-grpc-server
27 | spec:
28 | selector:
29 | app: greeter-grpc-server
30 | ports:
31 | - protocol: TCP
32 | port: 443
33 | targetPort: 50051
34 |
--------------------------------------------------------------------------------
/files/examples/inventory-route-bluegreen.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: HTTPRoute
3 | metadata:
4 | name: inventory
5 | spec:
6 | parentRefs:
7 | - name: my-hotel
8 | sectionName: http
9 | rules:
10 | - backendRefs:
11 | - name: inventory-ver1
12 | kind: Service
13 | port: 80
14 | weight: 10
15 | - name: inventory-ver2
16 | kind: ServiceImport
17 | weight: 90
18 |
--------------------------------------------------------------------------------
/files/examples/inventory-route.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: HTTPRoute
3 | metadata:
4 | name: inventory
5 | spec:
6 | parentRefs:
7 | - name: my-hotel
8 | sectionName: http
9 | rules:
10 | - backendRefs:
11 | - name: inventory-ver1
12 | kind: Service
13 | port: 80
14 | weight: 10
15 |
--------------------------------------------------------------------------------
/files/examples/inventory-ver1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: inventory-ver1
5 | labels:
6 | app: inventory-ver1
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: inventory-ver1
12 | template:
13 | metadata:
14 | labels:
15 | app: inventory-ver1
16 | spec:
17 | containers:
18 | - name: inventory-ver1
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "Inventory-ver1 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: inventory-ver1
30 | spec:
31 | selector:
32 | app: inventory-ver1
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/inventory-ver2-export.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceExport
3 | metadata:
4 | name: inventory-ver2
5 | annotations:
6 | application-networking.k8s.aws/federation: "amazon-vpc-lattice"
7 |
--------------------------------------------------------------------------------
/files/examples/inventory-ver2-import.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceImport
3 | metadata:
4 | name: inventory-ver2
5 | spec:
6 | type: ClusterSetIP
7 | ports:
8 | - port: 80
9 | protocol: TCP
10 |
--------------------------------------------------------------------------------
/files/examples/inventory-ver2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: inventory-ver2
5 | labels:
6 | app: inventory-ver2
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: inventory-ver2
12 | template:
13 | metadata:
14 | labels:
15 | app: inventory-ver2
16 | spec:
17 | containers:
18 | - name: inventory-ver2
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "Inventory-ver2 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: inventory-ver2
30 | spec:
31 | selector:
32 | app: inventory-ver2
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/my-gateway-tls-passthrough.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: Gateway
3 | metadata:
4 | name: my-hotel-tls-passthrough
5 | spec:
6 | gatewayClassName: amazon-vpc-lattice
7 | listeners:
8 | - name: http
9 | protocol: HTTP
10 | port: 80
11 | - name: tls
12 | protocol: TLS
13 | port: 443
14 | tls:
15 | mode: Passthrough
--------------------------------------------------------------------------------
/files/examples/my-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: Gateway
3 | metadata:
4 | name: my-gateway
5 | spec:
6 | gatewayClassName: amazon-vpc-lattice
7 | listeners:
8 | - name: http
9 | protocol: HTTP
10 | port: 80
11 |
--------------------------------------------------------------------------------
/files/examples/my-hotel-gateway-multi-listeners.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: Gateway
3 | metadata:
4 | name: my-hotel
5 | spec:
6 | gatewayClassName: amazon-vpc-lattice
7 | listeners:
8 | - name: http
9 | protocol: HTTP
10 | port: 80
11 | - name: https
12 | protocol: HTTPS
13 | port: 443
14 |
--------------------------------------------------------------------------------
/files/examples/my-hotel-gateway.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: Gateway
3 | metadata:
4 | name: my-hotel
5 | spec:
6 | gatewayClassName: amazon-vpc-lattice
7 | listeners:
8 | - name: http
9 | protocol: HTTP
10 | port: 80
11 |
--------------------------------------------------------------------------------
/files/examples/my-httproute.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: HTTPRoute
3 | metadata:
4 | name: my-httproute
5 | spec:
6 | parentRefs:
7 | - name: my-hotel
8 | sectionName: http
9 | rules:
10 | - backendRefs:
11 | - name: service-1
12 | kind: ServiceImport
13 | matches:
14 | - path:
15 | type: PathPrefix
16 | value: /service-1
17 | - backendRefs:
18 | - name: service-2
19 | kind: ServiceImport
20 | matches:
21 | - path:
22 | type: PathPrefix
23 | value: /service-2
24 |
--------------------------------------------------------------------------------
/files/examples/nginx-server-tls-passthrough.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-tls
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: nginx-tls
9 | replicas: 2
10 | template:
11 | metadata:
12 | labels:
13 | app: nginx-tls
14 | spec:
15 | containers:
16 | - name: nginx-tls
17 | image: public.ecr.aws/x2j8p8w7/lattice-test-server:latest
18 | ports:
19 | - containerPort: 443
20 |
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: nginx-tls
26 | spec:
27 | selector:
28 | app: nginx-tls
29 | ports:
30 | - protocol: TCP
31 | port: 443
32 | targetPort: 443
33 |
34 |
--------------------------------------------------------------------------------
/files/examples/parking.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: parking
5 | labels:
6 | app: parking
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: parking
12 | template:
13 | metadata:
14 | labels:
15 | app: parking
16 | spec:
17 | containers:
18 | - name: parking
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "parking handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: parking
30 | spec:
31 | selector:
32 | app: parking
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/rate-route-path.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1
2 | kind: HTTPRoute
3 | metadata:
4 | name: rates
5 | spec:
6 | parentRefs:
7 | - name: my-hotel
8 | sectionName: http
9 | rules:
10 | - backendRefs:
11 | - name: parking
12 | kind: Service
13 | port: 80
14 | matches:
15 | - path:
16 | type: PathPrefix
17 | value: /parking
18 | - backendRefs:
19 | - name: review
20 | kind: Service
21 | port: 80
22 | matches:
23 | - path:
24 | type: PathPrefix
25 | value: /review
26 |
--------------------------------------------------------------------------------
/files/examples/rate-tlsroute-bluegreen.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1alpha2
2 | kind: TLSRoute
3 | metadata:
4 | name: rate-tls-passthrough
5 | spec:
6 | hostnames:
7 | - tls-rate.my-test.com
8 | parentRefs:
9 | - name: my-hotel-tls-passthrough
10 | sectionName: tls
11 | rules:
12 | - backendRefs:
13 | - name: tls-rate1
14 | kind: Service
15 | port: 443
16 | weight: 10
17 | - name: tls-rate2
18 | kind: ServiceImport
19 | port: 443
20 | weight: 90
--------------------------------------------------------------------------------
/files/examples/review.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: review
5 | labels:
6 | app: review
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: review
12 | template:
13 | metadata:
14 | labels:
15 | app: review
16 | spec:
17 | containers:
18 | - name: aug24-review
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "review handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: review
30 | spec:
31 | selector:
32 | app: review
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/service-1-export.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceExport
3 | metadata:
4 | name: service-1
5 | annotations:
6 | application-networking.k8s.aws/federation: "amazon-vpc-lattice"
7 |
--------------------------------------------------------------------------------
/files/examples/service-1-import.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceImport
3 | metadata:
4 | name: service-1
5 | spec:
6 | type: ClusterSetIP
7 | ports:
8 | - port: 80
9 | protocol: TCP
10 |
--------------------------------------------------------------------------------
/files/examples/service-1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: service-1
5 | labels:
6 | app: service-1
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: service-1
12 | template:
13 | metadata:
14 | labels:
15 | app: service-1
16 | spec:
17 | containers:
18 | - name: service-1
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "service-1 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: service-1
30 | spec:
31 | selector:
32 | app: service-1
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/service-2-export.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceExport
3 | metadata:
4 | name: service-2
5 | annotations:
6 | application-networking.k8s.aws/federation: "amazon-vpc-lattice"
7 |
--------------------------------------------------------------------------------
/files/examples/service-2-import.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceImport
3 | metadata:
4 | name: service-2
5 | spec:
6 | type: ClusterSetIP
7 | ports:
8 | - port: 80
9 | protocol: TCP
10 |
--------------------------------------------------------------------------------
/files/examples/service-2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: service-2
5 | labels:
6 | app: service-2
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: service-2
12 | template:
13 | metadata:
14 | labels:
15 | app: service-2
16 | spec:
17 | containers:
18 | - name: service-2
19 | image: public.ecr.aws/x2j8p8w7/http-server:latest
20 | env:
21 | - name: PodName
22 | value: "service-2 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: service-2
30 | spec:
31 | selector:
32 | app: service-2
33 | ports:
34 | - protocol: TCP
35 | port: 80
36 | targetPort: 8090
37 |
--------------------------------------------------------------------------------
/files/examples/tls-rate1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: tls-rate1
5 | labels:
6 | app: tls-rate1
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: tls-rate1
12 | template:
13 | metadata:
14 | labels:
15 | app: tls-rate1
16 | spec:
17 | containers:
18 | - name: tls-rate1
19 | image: public.ecr.aws/x2j8p8w7/https-server:latest
20 | env:
21 | - name: PodName
22 | value: "tls-rate1 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: tls-rate1
30 | spec:
31 | selector:
32 | app: tls-rate1
33 | ports:
34 | - protocol: TCP
35 | port: 443
36 | targetPort: 443
--------------------------------------------------------------------------------
/files/examples/tls-rate2-export.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceExport
3 | metadata:
4 | name: tls-rate2
5 | annotations:
6 | application-networking.k8s.aws/federation: "amazon-vpc-lattice"
--------------------------------------------------------------------------------
/files/examples/tls-rate2-import.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: ServiceImport
3 | metadata:
4 | name: tls-rate2
5 | spec:
6 | type: ClusterSetIP
7 | ports:
8 | - port: 443
9 | protocol: TCP
--------------------------------------------------------------------------------
/files/examples/tls-rate2-targetgrouppolicy.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: application-networking.k8s.aws/v1alpha1
2 | kind: TargetGroupPolicy
3 | metadata:
4 | name: tls-rate2
5 | spec:
6 | targetRef:
7 | group: "application-networking.k8s.aws"
8 | kind: ServiceExport
9 | name: tls-rate2
10 | protocol: TCP
11 | healthCheck:
12 | enabled: false
--------------------------------------------------------------------------------
/files/examples/tls-rate2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: tls-rate2
5 | labels:
6 | app: tls-rate2
7 | spec:
8 | replicas: 2
9 | selector:
10 | matchLabels:
11 | app: tls-rate2
12 | template:
13 | metadata:
14 | labels:
15 | app: tls-rate2
16 | spec:
17 | containers:
18 | - name: tls-rate2
19 | image: public.ecr.aws/x2j8p8w7/https-server:latest
20 | env:
21 | - name: PodName
22 | value: "tls-rate2 handler pod"
23 |
24 |
25 | ---
26 | apiVersion: v1
27 | kind: Service
28 | metadata:
29 | name: tls-rate2
30 | spec:
31 | selector:
32 | app: tls-rate2
33 | ports:
34 | - protocol: TCP
35 | port: 443
36 | targetPort: 443
--------------------------------------------------------------------------------
/files/examples/tlsroute-nginx.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1alpha2
2 | kind: TLSRoute
3 | metadata:
4 | name: nginx-tls-route
5 | spec:
6 | hostnames:
7 | - nginx-test.my-test.com
8 | parentRefs:
9 | - name: my-hotel-tls-passthrough
10 | sectionName: tls
11 | rules:
12 | - backendRefs:
13 | - name: nginx-tls
14 | kind: Service
15 | port: 443
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
--------------------------------------------------------------------------------
/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | name: aws-gateway-controller-chart
3 | description: A Helm chart for the Gateway Controller for AWS VPC Lattice
4 | version: v1.1.1
5 | appVersion: v1.1.1
6 | home: https://github.com/aws/aws-application-networking-k8s
7 | icon: https://raw.githubusercontent.com/aws/eks-charts/master/docs/logo/aws.png
8 | sources:
9 | - https://github.com/aws/aws-application-networking-k8s
10 | maintainers:
11 | - name: AWS Application Networking Kubernetes project admins
12 | url: https://github.com/orgs/aws/teams/aws-application-networking-maintainer
13 | keywords:
14 | - aws
15 | - kubernetes
16 | - gateway-api
17 | - vpc-lattice
18 |
--------------------------------------------------------------------------------
/helm/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | {{ .Chart.Name }} has been installed.
2 | This chart deploys "{{ .Values.image.repository }}:{{ .Values.image.tags }}".
3 |
4 | Check its status by running:
5 | kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}"
6 |
7 | The controller is running in "{{ .Values.installScope }}" mode.
8 |
--------------------------------------------------------------------------------
/helm/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* The name of the application this chart installs */}}
2 | {{- define "app.name" -}}
3 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
4 | {{- end -}}
5 |
6 | {{/*
7 | Create a default fully qualified app name.
8 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
9 | If release name contains chart name it will be used as a full name.
10 | */}}
11 | {{- define "app.fullname" -}}
12 | {{- if .Values.fullnameOverride -}}
13 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
14 | {{- else -}}
15 | {{- $name := default .Chart.Name .Values.nameOverride -}}
16 | {{- if contains $name .Release.Name -}}
17 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}}
18 | {{- else -}}
19 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
20 | {{- end -}}
21 | {{- end -}}
22 | {{- end -}}
23 |
24 | {{/* The name and version as used by the chart label */}}
25 | {{- define "chart.name-version" -}}
26 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
27 | {{- end -}}
28 |
29 | {{/* The name of the service account to use */}}
30 | {{- define "service-account.name" -}}
31 | {{ default "default" .Values.serviceAccount.name }}
32 | {{- end -}}
33 |
34 | {{/* Import or generate certificates for webhook */}}
35 | {{- define "aws-gateway-controller.webhookTLS" -}}
36 | {{- if (and .Values.webhookTLS.caCert .Values.webhookTLS.cert .Values.webhookTLS.key) -}}
37 | caCert: {{ .Values.webhookTLS.caCert }}
38 | cert: {{ .Values.webhookTLS.cert }}
39 | key: {{ .Values.webhookTLS.key }}
40 | {{- else -}}
41 | {{- $ca := genCA "aws-gateway-controller-ca" 36500 -}}
42 | {{- $serviceDefaultName:= printf "webhook-service.%s.svc" .Release.Namespace -}}
43 | {{- $secretName := "webhook-cert" -}}
44 | {{- $altNames := list ($serviceDefaultName) (printf "%s.cluster.local" $serviceDefaultName) -}}
45 | {{- $cert := genSignedCert $serviceDefaultName nil $altNames 36500 $ca -}}
46 | caCert: {{ $ca.Cert | b64enc }}
47 | cert: {{ $cert.Cert | b64enc }}
48 | key: {{ $cert.Key | b64enc }}
49 | {{- end -}}
50 | {{- end -}}
51 |
--------------------------------------------------------------------------------
/helm/templates/cluster-role-binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | {{ if eq .Values.installScope "cluster" }}
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: {{ include "app.fullname" . }}
6 | roleRef:
7 | kind: ClusterRole
8 | {{ else }}
9 | kind: RoleBinding
10 | metadata:
11 | name: {{ include "app.fullname" . }}
12 | namespace: {{ .Release.Namespace }}
13 | roleRef:
14 | kind: Role
15 | {{ end }}
16 | apiGroup: rbac.authorization.k8s.io
17 | name: {{ include "app.fullname" . }}
18 | subjects:
19 | - kind: ServiceAccount
20 | name: {{ include "service-account.name" . }}
21 | namespace: {{ .Release.Namespace }}
22 |
--------------------------------------------------------------------------------
/helm/templates/metrics-service.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.metrics.service.create }}
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: {{ .Chart.Name | trunc 54 }}-metrics
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ include "app.name" . }}
9 | app.kubernetes.io/instance: {{ .Release.Name }}
10 | app.kubernetes.io/managed-by: Helm
11 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
12 | k8s-app: {{ include "app.name" . }}
13 | helm.sh/chart: {{ include "chart.name-version" . }}
14 | control-plane: controller
15 | spec:
16 | selector:
17 | app.kubernetes.io/name: {{ include "app.name" . }}
18 | app.kubernetes.io/instance: {{ .Release.Name }}
19 | app.kubernetes.io/managed-by: Helm
20 | k8s-app: {{ include "app.name" . }}
21 | {{- range $key, $value := .Values.deployment.labels }}
22 | {{ $key }}: {{ $value | quote }}
23 | {{- end }}
24 | type: {{ .Values.metrics.service.type }}
25 | ports:
26 | - name: metricsport
27 | port: 8080
28 | targetPort: http
29 | protocol: TCP
30 | {{- end }}
31 |
--------------------------------------------------------------------------------
/helm/templates/pdb.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.pdb.enabled -}}
2 | apiVersion: policy/v1
3 | kind: PodDisruptionBudget
4 | metadata:
5 | name: {{ include "app.fullname" . }}
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ include "app.name" . }}
9 | app.kubernetes.io/instance: {{ .Release.Name }}
10 | app.kubernetes.io/managed-by: Helm
11 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
12 | k8s-app: {{ include "app.name" . }}
13 | helm.sh/chart: {{ include "chart.name-version" . }}
14 | control-plane: controller
15 | spec:
16 | selector:
17 | matchLabels:
18 | app.kubernetes.io/name: {{ include "app.name" . }}
19 | app.kubernetes.io/instance: {{ .Release.Name }}
20 | {{- with .Values.pdb.minAvailable }}
21 | minAvailable: {{ . }}
22 | {{- end }}
23 | {{- with .Values.pdb.maxUnavailable }}
24 | maxUnavailable: {{ . }}
25 | {{- end }}
26 | {{- end -}}
27 |
--------------------------------------------------------------------------------
/helm/templates/service-account.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: {{ include "app.name" . }}
7 | app.kubernetes.io/instance: {{ .Release.Name }}
8 | app.kubernetes.io/managed-by: Helm
9 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
10 | k8s-app: {{ include "app.name" . }}
11 | helm.sh/chart: {{ include "chart.name-version" . }}
12 | name: {{ include "service-account.name" . }}
13 | namespace: {{ .Release.Namespace }}
14 | annotations:
15 | {{- range $key, $value := .Values.serviceAccount.annotations }}
16 | {{ $key }}: {{ $value | quote }}
17 | {{- end }}
18 | {{- end }}
19 |
--------------------------------------------------------------------------------
/helm/templates/webhook.yaml:
--------------------------------------------------------------------------------
1 | {{ $tls := fromYaml ( include "aws-gateway-controller.webhookTLS" . ) }}
2 | ---
3 | apiVersion: admissionregistration.k8s.io/v1
4 | kind: MutatingWebhookConfiguration
5 | metadata:
6 | name: aws-appnet-gwc-mutating-webhook
7 | webhooks:
8 | - admissionReviewVersions:
9 | - v1
10 | clientConfig:
11 | caBundle: {{ $tls.caCert }}
12 | service:
13 | name: webhook-service
14 | namespace: {{ .Release.Namespace }}
15 | path: /mutate-pod
16 | failurePolicy: Fail
17 | name: mpod.gwc.k8s.aws
18 | rules:
19 | - apiGroups:
20 | - ""
21 | apiVersions:
22 | - v1
23 | operations:
24 | - CREATE
25 | resources:
26 | - pods
27 | sideEffects: None
28 | namespaceSelector:
29 | matchExpressions:
30 | - key: application-networking.k8s.aws/pod-readiness-gate-inject
31 | operator: In
32 | values:
33 | - enabled
34 | objectSelector:
35 | matchExpressions:
36 | - key: app.kubernetes.io/name
37 | operator: NotIn
38 | values:
39 | - gateway-api-controller
40 | ---
41 | apiVersion: v1
42 | kind: Service
43 | metadata:
44 | name: webhook-service
45 | namespace: {{ .Release.Namespace }}
46 | spec:
47 | ports:
48 | - port: 443
49 | targetPort: webhook-server
50 | selector:
51 | control-plane: gateway-api-controller
52 | ---
53 | apiVersion: v1
54 | kind: Secret
55 | metadata:
56 | name: webhook-cert
57 | namespace: {{ .Release.Namespace }}
58 | type: kubernetes.io/tls
59 | data:
60 | ca.crt: {{ $tls.caCert }}
61 | tls.crt: {{ $tls.cert }}
62 | tls.key: {{ $tls.key }}
--------------------------------------------------------------------------------
/mocks/controller-runtime/client/generate.go:
--------------------------------------------------------------------------------
1 | package mock_client
2 |
3 | //go:generate mockgen -package mock_client -destination client_mocks.go sigs.k8s.io/controller-runtime/pkg/client Client
4 | //go:generate mockgen -package mock_client -destination record_mock.go k8s.io/client-go/tools/record EventRecorder
5 |
--------------------------------------------------------------------------------
/pkg/apis/applicationnetworking/v1alpha1/common.go:
--------------------------------------------------------------------------------
1 | package v1alpha1
2 |
3 | func toPtrSlice[T any](s []T) []*T {
4 | ps := make([]*T, len(s))
5 | for i, t := range s {
6 | ct := t
7 | ps[i] = &ct
8 | }
9 | return ps
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/apis/applicationnetworking/v1alpha1/common_test.go:
--------------------------------------------------------------------------------
1 | package v1alpha1
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestToPtrSlice(t *testing.T) {
10 |
11 | type A struct {
12 | x int
13 | }
14 |
15 | type test struct {
16 | name string
17 | in []A
18 | want []*A
19 | }
20 |
21 | tests := []test{
22 | {"empty", []A{}, []*A{}},
23 | {"single item", []A{{1}}, []*A{{1}}},
24 | {"multiple items", []A{{1}, {2}, {3}}, []*A{{1}, {2}, {3}}},
25 | }
26 |
27 | for _, tt := range tests {
28 | t.Run(tt.name, func(t *testing.T) {
29 | assert.Equal(t, toPtrSlice(tt.in), tt.want)
30 | })
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/apis/applicationnetworking/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | // +kubebuilder:object:generate=true
2 | // +groupName=application-networking.k8s.aws
3 | package v1alpha1
4 |
--------------------------------------------------------------------------------
/pkg/aws/services/tagging_mocks.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/aws/aws-application-networking-k8s/pkg/aws/services (interfaces: Tagging)
3 |
4 | // Package services is a generated GoMock package.
5 | package services
6 |
7 | import (
8 | context "context"
9 | reflect "reflect"
10 |
11 | gomock "github.com/golang/mock/gomock"
12 | )
13 |
14 | // MockTagging is a mock of Tagging interface.
15 | type MockTagging struct {
16 | ctrl *gomock.Controller
17 | recorder *MockTaggingMockRecorder
18 | }
19 |
20 | // MockTaggingMockRecorder is the mock recorder for MockTagging.
21 | type MockTaggingMockRecorder struct {
22 | mock *MockTagging
23 | }
24 |
25 | // NewMockTagging creates a new mock instance.
26 | func NewMockTagging(ctrl *gomock.Controller) *MockTagging {
27 | mock := &MockTagging{ctrl: ctrl}
28 | mock.recorder = &MockTaggingMockRecorder{mock}
29 | return mock
30 | }
31 |
32 | // EXPECT returns an object that allows the caller to indicate expected use.
33 | func (m *MockTagging) EXPECT() *MockTaggingMockRecorder {
34 | return m.recorder
35 | }
36 |
37 | // FindResourcesByTags mocks base method.
38 | func (m *MockTagging) FindResourcesByTags(arg0 context.Context, arg1 ResourceType, arg2 map[string]*string) ([]string, error) {
39 | m.ctrl.T.Helper()
40 | ret := m.ctrl.Call(m, "FindResourcesByTags", arg0, arg1, arg2)
41 | ret0, _ := ret[0].([]string)
42 | ret1, _ := ret[1].(error)
43 | return ret0, ret1
44 | }
45 |
46 | // FindResourcesByTags indicates an expected call of FindResourcesByTags.
47 | func (mr *MockTaggingMockRecorder) FindResourcesByTags(arg0, arg1, arg2 interface{}) *gomock.Call {
48 | mr.mock.ctrl.T.Helper()
49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindResourcesByTags", reflect.TypeOf((*MockTagging)(nil).FindResourcesByTags), arg0, arg1, arg2)
50 | }
51 |
52 | // GetTagsForArns mocks base method.
53 | func (m *MockTagging) GetTagsForArns(arg0 context.Context, arg1 []string) (map[string]map[string]*string, error) {
54 | m.ctrl.T.Helper()
55 | ret := m.ctrl.Call(m, "GetTagsForArns", arg0, arg1)
56 | ret0, _ := ret[0].(map[string]map[string]*string)
57 | ret1, _ := ret[1].(error)
58 | return ret0, ret1
59 | }
60 |
61 | // GetTagsForArns indicates an expected call of GetTagsForArns.
62 | func (mr *MockTaggingMockRecorder) GetTagsForArns(arg0, arg1 interface{}) *gomock.Call {
63 | mr.mock.ctrl.T.Helper()
64 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTagsForArns", reflect.TypeOf((*MockTagging)(nil).GetTagsForArns), arg0, arg1)
65 | }
66 |
--------------------------------------------------------------------------------
/pkg/config/ec2_metadata.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/aws/aws-sdk-go/aws/ec2metadata"
8 | "github.com/aws/aws-sdk-go/aws/session"
9 | )
10 |
11 | type EC2Metadata interface {
12 | Region() (string, error)
13 | VpcID() (string, error)
14 | AccountId() (string, error)
15 | }
16 |
17 | // NewEC2Metadata constructs new EC2Metadata implementation.
18 | func NewEC2Metadata(session *session.Session) EC2Metadata {
19 | return &defaultEC2Metadata{
20 | EC2Metadata: ec2metadata.New(session),
21 | }
22 | }
23 |
24 | type defaultEC2Metadata struct {
25 | *ec2metadata.EC2Metadata
26 | }
27 |
28 | func (c *defaultEC2Metadata) VpcID() (string, error) {
29 | mac, err := c.GetMetadata("mac")
30 | if err != nil {
31 | return "", err
32 | }
33 | vpcID, err := c.GetMetadata(fmt.Sprintf("network/interfaces/macs/%s/vpc-id", mac))
34 | if err != nil {
35 | return "", err
36 | }
37 | return vpcID, nil
38 | }
39 |
40 | func (c *defaultEC2Metadata) Region() (string, error) {
41 | region, err := c.GetMetadata("placement/region")
42 | if err != nil {
43 | return "", err
44 | }
45 | return region, nil
46 | }
47 |
48 | func (c *defaultEC2Metadata) AccountId() (string, error) {
49 | ec2Info, err := c.GetMetadata("identity-credentials/ec2/info")
50 | type accountInfo struct {
51 | Code string `json:"code"`
52 | LastUpdated string `json:"LastUpdated"`
53 | AccountId string `json:"AccountId"`
54 | }
55 |
56 | var acc accountInfo
57 | json.Unmarshal([]byte(ec2Info), &acc)
58 | if err != nil {
59 | return "", err
60 | }
61 | return acc.AccountId, nil
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/controllers/errors.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import "errors"
4 |
5 | var (
6 | GroupNameError = errors.New("wrong group name")
7 | KindError = errors.New("target kind error")
8 | TargetRefNotFound = errors.New("targetRef not found")
9 | TargetRefConflict = errors.New("targetRef has conflict")
10 | )
11 |
--------------------------------------------------------------------------------
/pkg/controllers/eventhandlers/gatewayclass.go:
--------------------------------------------------------------------------------
1 | package eventhandlers
2 |
3 | import (
4 | "context"
5 |
6 | "k8s.io/apimachinery/pkg/types"
7 | "k8s.io/client-go/util/workqueue"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 | "sigs.k8s.io/controller-runtime/pkg/event"
10 | "sigs.k8s.io/controller-runtime/pkg/handler"
11 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
12 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
13 |
14 | "github.com/aws/aws-application-networking-k8s/pkg/config"
15 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
16 | )
17 |
18 | func NewEnqueueRequestsForGatewayClassEvent(log gwlog.Logger, client client.Client) handler.EventHandler {
19 | return &enqueueRequestsForGatewayClassEvent{
20 | log: log,
21 | client: client,
22 | }
23 | }
24 |
25 | type enqueueRequestsForGatewayClassEvent struct {
26 | log gwlog.Logger
27 | client client.Client
28 | }
29 |
30 | func (h *enqueueRequestsForGatewayClassEvent) Create(ctx context.Context, e event.CreateEvent, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
31 | gwClassNew := e.Object.(*gwv1.GatewayClass)
32 | h.enqueueImpactedGateway(ctx, queue, gwClassNew)
33 | }
34 |
35 | func (h *enqueueRequestsForGatewayClassEvent) Update(ctx context.Context, e event.UpdateEvent, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
36 | }
37 |
38 | func (h *enqueueRequestsForGatewayClassEvent) Delete(ctx context.Context, e event.DeleteEvent, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
39 | }
40 |
41 | func (h *enqueueRequestsForGatewayClassEvent) Generic(ctx context.Context, e event.GenericEvent, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
42 | }
43 |
44 | func (h *enqueueRequestsForGatewayClassEvent) enqueueImpactedGateway(
45 | ctx context.Context,
46 | queue workqueue.TypedRateLimitingInterface[reconcile.Request],
47 | gwClass *gwv1.GatewayClass,
48 | ) {
49 | gwList := &gwv1.GatewayList{}
50 | err := h.client.List(ctx, gwList)
51 | if err != nil {
52 | h.log.Errorf(ctx, "Error listing Gateways during GatewayClass event %s", err)
53 | return
54 | }
55 |
56 | for _, gw := range gwList.Items {
57 | if string(gw.Spec.GatewayClassName) == gwClass.Name {
58 | if gwClass.Spec.ControllerName == config.LatticeGatewayControllerName {
59 | h.log.Debugf(ctx, "Found matching gateway, %s-%s", gw.Name, gw.Namespace)
60 | queue.Add(reconcile.Request{
61 | NamespacedName: types.NamespacedName{
62 | Namespace: gw.Namespace,
63 | Name: gw.Name,
64 | },
65 | })
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/pkg/controllers/eventhandlers/serviceimport.go:
--------------------------------------------------------------------------------
1 | package eventhandlers
2 |
3 | import (
4 | "context"
5 |
6 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
7 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
8 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
9 |
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 | "sigs.k8s.io/controller-runtime/pkg/handler"
12 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
13 |
14 | "github.com/aws/aws-application-networking-k8s/pkg/k8s"
15 | )
16 |
17 | type serviceImportEventHandler struct {
18 | log gwlog.Logger
19 | client client.Client
20 | mapper *resourceMapper
21 | }
22 |
23 | func NewServiceImportEventHandler(log gwlog.Logger, client client.Client) *serviceImportEventHandler {
24 | return &serviceImportEventHandler{
25 | log: log,
26 | client: client,
27 | mapper: &resourceMapper{log: log, client: client},
28 | }
29 | }
30 |
31 | func (h *serviceImportEventHandler) MapToRoute(routeType core.RouteType) handler.EventHandler {
32 | return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
33 | return h.mapToRoute(ctx, obj, routeType)
34 | })
35 | }
36 |
37 | func (h *serviceImportEventHandler) mapToRoute(ctx context.Context, obj client.Object, routeType core.RouteType) []reconcile.Request {
38 | routes := h.mapper.ServiceImportToRoutes(ctx, obj.(*anv1alpha1.ServiceImport), routeType)
39 |
40 | var requests []reconcile.Request
41 | for _, route := range routes {
42 | routeName := k8s.NamespacedName(route.K8sObject())
43 | requests = append(requests, reconcile.Request{NamespacedName: routeName})
44 | h.log.Infow(ctx, "ServiceImport resource change triggered Route update",
45 | "serviceName", obj.GetNamespace()+"/"+obj.GetName(), "routeName", routeName, "routeType", routeType)
46 | }
47 | return requests
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/controllers/eventhandlers/serviceimport_test.go:
--------------------------------------------------------------------------------
1 | package eventhandlers
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/golang/mock/gomock"
8 | "github.com/stretchr/testify/assert"
9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | "k8s.io/utils/ptr"
11 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
12 |
13 | mock_client "github.com/aws/aws-application-networking-k8s/mocks/controller-runtime/client"
14 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
15 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
16 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
17 | )
18 |
19 | func TestServiceImportEventHandler_MapToRoute(t *testing.T) {
20 | c := gomock.NewController(t)
21 | defer c.Finish()
22 |
23 | routes := []gwv1.HTTPRoute{
24 | createHTTPRoute("valid-route", "ns1", gwv1.BackendObjectReference{
25 | Group: (*gwv1.Group)(ptr.To("application-networking.k8s.aws")),
26 | Kind: (*gwv1.Kind)(ptr.To("ServiceImport")),
27 | Namespace: (*gwv1.Namespace)(ptr.To("ns1")),
28 | Name: "test-service",
29 | }),
30 | }
31 | mockClient := mock_client.NewMockClient(c)
32 | h := NewServiceImportEventHandler(gwlog.FallbackLogger, mockClient)
33 | mockClient.EXPECT().List(gomock.Any(), gomock.Any()).DoAndReturn(
34 | func(ctx context.Context, routeList *gwv1.HTTPRouteList, _ ...interface{}) error {
35 | routeList.Items = append(routeList.Items, routes...)
36 | return nil
37 | },
38 | ).AnyTimes()
39 |
40 | reqs := h.mapToRoute(context.Background(), &anv1alpha1.ServiceImport{
41 | ObjectMeta: metav1.ObjectMeta{
42 | Name: "test-service",
43 | Namespace: "ns1",
44 | },
45 | }, core.HttpRouteType)
46 | assert.Len(t, reqs, 1)
47 | assert.Equal(t, "valid-route", reqs[0].Name)
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/controllers/eventhandlers/vpc_association_policy.go:
--------------------------------------------------------------------------------
1 | package eventhandlers
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
7 | "github.com/aws/aws-application-networking-k8s/pkg/k8s"
8 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
9 |
10 | "sigs.k8s.io/controller-runtime/pkg/client"
11 | "sigs.k8s.io/controller-runtime/pkg/handler"
12 | "sigs.k8s.io/controller-runtime/pkg/reconcile"
13 | )
14 |
15 | type vpcAssociationPolicyEventHandler struct {
16 | log gwlog.Logger
17 | client client.Client
18 | mapper *resourceMapper
19 | }
20 |
21 | func NewVpcAssociationPolicyEventHandler(log gwlog.Logger, client client.Client) *vpcAssociationPolicyEventHandler {
22 | return &vpcAssociationPolicyEventHandler{log: log, client: client,
23 | mapper: &resourceMapper{log: log, client: client}}
24 | }
25 |
26 | func (h *vpcAssociationPolicyEventHandler) MapToGateway() handler.EventHandler {
27 | return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
28 | if vap, ok := obj.(*v1alpha1.VpcAssociationPolicy); ok {
29 | if gw := h.mapper.VpcAssociationPolicyToGateway(ctx, vap); gw != nil {
30 | return []reconcile.Request{{NamespacedName: k8s.NamespacedName(gw)}}
31 | }
32 | }
33 | return nil
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/controllers/iamauthpolicy_controller_test.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
--------------------------------------------------------------------------------
/pkg/controllers/pod_controller.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package controllers
18 |
19 | import (
20 | "context"
21 |
22 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
23 | corev1 "k8s.io/api/core/v1"
24 | "k8s.io/apimachinery/pkg/runtime"
25 | ctrl "sigs.k8s.io/controller-runtime"
26 | "sigs.k8s.io/controller-runtime/pkg/client"
27 | )
28 |
29 | type podReconciler struct {
30 | log gwlog.Logger
31 | client client.Client
32 | scheme *runtime.Scheme
33 | }
34 |
35 | func RegisterPodController(log gwlog.Logger, mgr ctrl.Manager) error {
36 | pr := &podReconciler{
37 | log: log,
38 | client: mgr.GetClient(),
39 | scheme: mgr.GetScheme(),
40 | }
41 | err := ctrl.NewControllerManagedBy(mgr).
42 | For(&corev1.Pod{}).
43 | Complete(pr)
44 | return err
45 | }
46 |
47 | //+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
48 | //+kubebuilder:rbac:groups=core,resources=pods/status,verbs=get;update;patch
49 | //+kubebuilder:rbac:groups=core,resources=pods/finalizers,verbs=update
50 |
51 | func (r *podReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
52 | pod := &corev1.Pod{}
53 | if err := r.client.Get(ctx, req.NamespacedName, pod); err != nil {
54 | return ctrl.Result{}, client.IgnoreNotFound(err)
55 |
56 | }
57 | return ctrl.Result{}, nil
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/controllers/suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package controllers
18 |
19 | import (
20 | "path/filepath"
21 | "testing"
22 |
23 | . "github.com/onsi/ginkgo"
24 | . "github.com/onsi/gomega"
25 | corev1 "k8s.io/api/core/v1"
26 | "k8s.io/client-go/kubernetes/scheme"
27 | "sigs.k8s.io/controller-runtime/pkg/client"
28 | "sigs.k8s.io/controller-runtime/pkg/envtest"
29 | logf "sigs.k8s.io/controller-runtime/pkg/log"
30 | "sigs.k8s.io/controller-runtime/pkg/log/zap"
31 | //+kubebuilder:scaffold:imports
32 | )
33 |
34 | var k8sClient client.Client
35 | var testEnv *envtest.Environment
36 |
37 | func TestAPIs(t *testing.T) {
38 | RegisterFailHandler(Fail)
39 |
40 | /* TODO
41 | RunSpecsWithDefaultAndCustomReporters(t,
42 | "Controller Suite",
43 | []Reporter{printer.NewlineReporter{}})
44 |
45 | */
46 | }
47 |
48 | var _ = BeforeSuite(func() {
49 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
50 |
51 | By("bootstrapping test environment")
52 | testEnv = &envtest.Environment{
53 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
54 | ErrorIfCRDPathMissing: false,
55 | }
56 |
57 | cfg, err := testEnv.Start()
58 | Expect(err).NotTo(HaveOccurred())
59 | Expect(cfg).NotTo(BeNil())
60 |
61 | err = corev1.AddToScheme(scheme.Scheme)
62 | Expect(err).NotTo(HaveOccurred())
63 |
64 | //+kubebuilder:scaffold:scheme
65 |
66 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
67 | Expect(err).NotTo(HaveOccurred())
68 | Expect(k8sClient).NotTo(BeNil())
69 |
70 | }, 60)
71 |
72 | var _ = AfterSuite(func() {
73 | By("tearing down the test environment")
74 | err := testEnv.Stop()
75 | Expect(err).NotTo(HaveOccurred())
76 | })
77 |
--------------------------------------------------------------------------------
/pkg/controllers/targetgrouppolicy_controller.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "context"
5 |
6 | corev1 "k8s.io/api/core/v1"
7 | ctrl "sigs.k8s.io/controller-runtime"
8 | "sigs.k8s.io/controller-runtime/pkg/builder"
9 | "sigs.k8s.io/controller-runtime/pkg/client"
10 | "sigs.k8s.io/controller-runtime/pkg/predicate"
11 |
12 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
13 | policy "github.com/aws/aws-application-networking-k8s/pkg/k8s/policyhelper"
14 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
15 | )
16 |
17 | type (
18 | TGP = anv1alpha1.TargetGroupPolicy
19 | )
20 |
21 | type TargetGroupPolicyController struct {
22 | log gwlog.Logger
23 | client client.Client
24 | ph *policy.PolicyHandler[*TGP]
25 | }
26 |
27 | func RegisterTargetGroupPolicyController(log gwlog.Logger, mgr ctrl.Manager) error {
28 | ph := policy.NewTargetGroupPolicyHandler(log, mgr.GetClient())
29 | controller := &TargetGroupPolicyController{
30 | log: log,
31 | client: mgr.GetClient(),
32 | ph: ph,
33 | }
34 |
35 | b := ctrl.NewControllerManagedBy(mgr).
36 | For(&TGP{}, builder.WithPredicates(predicate.GenerationChangedPredicate{}))
37 | ph.AddWatchers(b, &corev1.Service{})
38 | ph.AddWatchers(b, &anv1alpha1.ServiceExport{})
39 |
40 | return b.Complete(controller)
41 | }
42 |
43 | func (c *TargetGroupPolicyController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
44 | ctx = gwlog.StartReconcileTrace(ctx, c.log, "targetgrouppolicy", req.Name, req.Namespace)
45 | defer func() {
46 | gwlog.EndReconcileTrace(ctx, c.log)
47 | }()
48 |
49 | tgPolicy := &TGP{}
50 | err := c.client.Get(ctx, req.NamespacedName, tgPolicy)
51 | if err != nil {
52 | return ctrl.Result{}, client.IgnoreNotFound(err)
53 | }
54 | c.log.Infow(ctx, "reconcile target group policy", "req", req, "targetRef", tgPolicy.Spec.TargetRef)
55 |
56 | _, err = c.ph.ValidateAndUpdateCondition(ctx, tgPolicy)
57 | if err != nil {
58 | return ctrl.Result{}, err
59 | }
60 |
61 | c.log.Infow(ctx, "reconciled target group policy",
62 | "req", req,
63 | "targetRef", tgPolicy.Spec.TargetRef,
64 | )
65 | return ctrl.Result{}, nil
66 | }
67 |
--------------------------------------------------------------------------------
/pkg/deploy/externaldns/dnsendpoint_manager_mock.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/aws/aws-application-networking-k8s/pkg/deploy/externaldns (interfaces: DnsEndpointManager)
3 |
4 | // Package externaldns is a generated GoMock package.
5 | package externaldns
6 |
7 | import (
8 | context "context"
9 | reflect "reflect"
10 |
11 | lattice "github.com/aws/aws-application-networking-k8s/pkg/model/lattice"
12 | gomock "github.com/golang/mock/gomock"
13 | )
14 |
15 | // MockDnsEndpointManager is a mock of DnsEndpointManager interface.
16 | type MockDnsEndpointManager struct {
17 | ctrl *gomock.Controller
18 | recorder *MockDnsEndpointManagerMockRecorder
19 | }
20 |
21 | // MockDnsEndpointManagerMockRecorder is the mock recorder for MockDnsEndpointManager.
22 | type MockDnsEndpointManagerMockRecorder struct {
23 | mock *MockDnsEndpointManager
24 | }
25 |
26 | // NewMockDnsEndpointManager creates a new mock instance.
27 | func NewMockDnsEndpointManager(ctrl *gomock.Controller) *MockDnsEndpointManager {
28 | mock := &MockDnsEndpointManager{ctrl: ctrl}
29 | mock.recorder = &MockDnsEndpointManagerMockRecorder{mock}
30 | return mock
31 | }
32 |
33 | // EXPECT returns an object that allows the caller to indicate expected use.
34 | func (m *MockDnsEndpointManager) EXPECT() *MockDnsEndpointManagerMockRecorder {
35 | return m.recorder
36 | }
37 |
38 | // Create mocks base method.
39 | func (m *MockDnsEndpointManager) Create(arg0 context.Context, arg1 *lattice.Service) error {
40 | m.ctrl.T.Helper()
41 | ret := m.ctrl.Call(m, "Create", arg0, arg1)
42 | ret0, _ := ret[0].(error)
43 | return ret0
44 | }
45 |
46 | // Create indicates an expected call of Create.
47 | func (mr *MockDnsEndpointManagerMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call {
48 | mr.mock.ctrl.T.Helper()
49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockDnsEndpointManager)(nil).Create), arg0, arg1)
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/access_log_subscription_synthesizer.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "context"
5 |
6 | "sigs.k8s.io/controller-runtime/pkg/client"
7 |
8 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
9 | model "github.com/aws/aws-application-networking-k8s/pkg/model/lattice"
10 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
11 | )
12 |
13 | type accessLogSubscriptionSynthesizer struct {
14 | log gwlog.Logger
15 | client client.Client
16 | accessLogSubscriptionManager AccessLogSubscriptionManager
17 | stack core.Stack
18 | }
19 |
20 | func NewAccessLogSubscriptionSynthesizer(
21 | log gwlog.Logger,
22 | client client.Client,
23 | accessLogSubscriptionManager AccessLogSubscriptionManager,
24 | stack core.Stack,
25 | ) *accessLogSubscriptionSynthesizer {
26 | return &accessLogSubscriptionSynthesizer{
27 | log: log,
28 | client: client,
29 | accessLogSubscriptionManager: accessLogSubscriptionManager,
30 | stack: stack,
31 | }
32 | }
33 |
34 | func (s *accessLogSubscriptionSynthesizer) Synthesize(ctx context.Context) error {
35 | var accessLogSubscriptions []*model.AccessLogSubscription
36 | err := s.stack.ListResources(&accessLogSubscriptions)
37 | if err != nil {
38 | return err
39 | }
40 |
41 | for _, als := range accessLogSubscriptions {
42 | switch als.Spec.EventType {
43 | case core.CreateEvent:
44 | s.log.Debugf(ctx, "Started creating Access Log Subscription %s", als.ID())
45 | alsStatus, err := s.accessLogSubscriptionManager.Create(ctx, als)
46 | if err != nil {
47 | return err
48 | }
49 | als.Status = alsStatus
50 | case core.UpdateEvent:
51 | s.log.Debugf(ctx, "Started updating Access Log Subscription %s", als.ID())
52 | alsStatus, err := s.accessLogSubscriptionManager.Update(ctx, als)
53 | if err != nil {
54 | return err
55 | }
56 | als.Status = alsStatus
57 | case core.DeleteEvent:
58 | s.log.Debugf(ctx, "Started deleting Access Log Subscription %s", als.ID())
59 | if als.Status == nil {
60 | s.log.Debugf(ctx, "Ignoring deletion of Access Log Subscription because als %s has no ARN", als.ID())
61 | return nil
62 | }
63 | err := s.accessLogSubscriptionManager.Delete(ctx, als.Status.Arn)
64 | if err != nil {
65 | return err
66 | }
67 | }
68 | }
69 |
70 | return nil
71 | }
72 |
73 | func (s *accessLogSubscriptionSynthesizer) PostSynthesize(ctx context.Context) error {
74 | // nothing to do here
75 | return nil
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/config_test.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import pkg_aws "github.com/aws/aws-application-networking-k8s/pkg/aws"
4 |
5 | var TestCloudConfig = pkg_aws.CloudConfig{
6 | VpcId: "vpc-id",
7 | AccountId: "account-id",
8 | Region: "region",
9 | ClusterName: "cluster",
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/error.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import "errors"
4 |
5 | const (
6 | LATTICE_RETRY = "LATTICE_RETRY"
7 | )
8 |
9 | var RetryErr = errors.New(LATTICE_RETRY)
10 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/iamauthpolicy_manager_test.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/service_manager_mock.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/aws/aws-application-networking-k8s/pkg/deploy/lattice (interfaces: ServiceManager)
3 |
4 | // Package lattice is a generated GoMock package.
5 | package lattice
6 |
7 | import (
8 | context "context"
9 | reflect "reflect"
10 |
11 | lattice "github.com/aws/aws-application-networking-k8s/pkg/model/lattice"
12 | gomock "github.com/golang/mock/gomock"
13 | )
14 |
15 | // MockServiceManager is a mock of ServiceManager interface.
16 | type MockServiceManager struct {
17 | ctrl *gomock.Controller
18 | recorder *MockServiceManagerMockRecorder
19 | }
20 |
21 | // MockServiceManagerMockRecorder is the mock recorder for MockServiceManager.
22 | type MockServiceManagerMockRecorder struct {
23 | mock *MockServiceManager
24 | }
25 |
26 | // NewMockServiceManager creates a new mock instance.
27 | func NewMockServiceManager(ctrl *gomock.Controller) *MockServiceManager {
28 | mock := &MockServiceManager{ctrl: ctrl}
29 | mock.recorder = &MockServiceManagerMockRecorder{mock}
30 | return mock
31 | }
32 |
33 | // EXPECT returns an object that allows the caller to indicate expected use.
34 | func (m *MockServiceManager) EXPECT() *MockServiceManagerMockRecorder {
35 | return m.recorder
36 | }
37 |
38 | // Delete mocks base method.
39 | func (m *MockServiceManager) Delete(arg0 context.Context, arg1 *lattice.Service) error {
40 | m.ctrl.T.Helper()
41 | ret := m.ctrl.Call(m, "Delete", arg0, arg1)
42 | ret0, _ := ret[0].(error)
43 | return ret0
44 | }
45 |
46 | // Delete indicates an expected call of Delete.
47 | func (mr *MockServiceManagerMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call {
48 | mr.mock.ctrl.T.Helper()
49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockServiceManager)(nil).Delete), arg0, arg1)
50 | }
51 |
52 | // Upsert mocks base method.
53 | func (m *MockServiceManager) Upsert(arg0 context.Context, arg1 *lattice.Service) (lattice.ServiceStatus, error) {
54 | m.ctrl.T.Helper()
55 | ret := m.ctrl.Call(m, "Upsert", arg0, arg1)
56 | ret0, _ := ret[0].(lattice.ServiceStatus)
57 | ret1, _ := ret[1].(error)
58 | return ret0, ret1
59 | }
60 |
61 | // Upsert indicates an expected call of Upsert.
62 | func (mr *MockServiceManagerMockRecorder) Upsert(arg0, arg1 interface{}) *gomock.Call {
63 | mr.mock.ctrl.T.Helper()
64 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upsert", reflect.TypeOf((*MockServiceManager)(nil).Upsert), arg0, arg1)
65 | }
66 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/service_synthesizer.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 |
8 | "github.com/aws/aws-application-networking-k8s/pkg/utils"
9 |
10 | "github.com/aws/aws-application-networking-k8s/pkg/deploy/externaldns"
11 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
12 | model "github.com/aws/aws-application-networking-k8s/pkg/model/lattice"
13 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
14 | )
15 |
16 | func NewServiceSynthesizer(
17 | log gwlog.Logger,
18 | serviceManager ServiceManager,
19 | dnsEndpointManager externaldns.DnsEndpointManager,
20 | stack core.Stack,
21 | ) *serviceSynthesizer {
22 | return &serviceSynthesizer{
23 | log: log,
24 | serviceManager: serviceManager,
25 | dnsEndpointManager: dnsEndpointManager,
26 | stack: stack,
27 | }
28 | }
29 |
30 | type serviceSynthesizer struct {
31 | log gwlog.Logger
32 | serviceManager ServiceManager
33 | dnsEndpointManager externaldns.DnsEndpointManager
34 | stack core.Stack
35 | }
36 |
37 | func (s *serviceSynthesizer) Synthesize(ctx context.Context) error {
38 | var resServices []*model.Service
39 | s.stack.ListResources(&resServices)
40 |
41 | var svcErr error
42 | for _, resService := range resServices {
43 | svcName := utils.LatticeServiceName(resService.Spec.RouteName, resService.Spec.RouteNamespace)
44 | s.log.Debugf(ctx, "Synthesizing service: %s", svcName)
45 | if resService.IsDeleted {
46 | err := s.serviceManager.Delete(ctx, resService)
47 | if err != nil {
48 | svcErr = errors.Join(svcErr,
49 | fmt.Errorf("failed ServiceManager.Delete %s due to %w", svcName, err))
50 | continue
51 | }
52 | } else {
53 | serviceStatus, err := s.serviceManager.Upsert(ctx, resService)
54 | if err != nil {
55 | svcErr = errors.Join(svcErr,
56 | fmt.Errorf("failed ServiceManager.Upsert %s due to %w", svcName, err))
57 | continue
58 | }
59 |
60 | resService.Status = &serviceStatus
61 | err = s.dnsEndpointManager.Create(ctx, resService)
62 | if err != nil {
63 | svcErr = errors.Join(svcErr,
64 | fmt.Errorf("failed DnsEndpointManager.Create %s due to %w", svcName, err))
65 | continue
66 | }
67 | }
68 | }
69 |
70 | return svcErr
71 | }
72 |
73 | func (s *serviceSynthesizer) PostSynthesize(ctx context.Context) error {
74 | // nothing to do here
75 | return nil
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/deploy/lattice/targets_manager_mock.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/aws/aws-application-networking-k8s/pkg/deploy/lattice (interfaces: TargetsManager)
3 |
4 | // Package lattice is a generated GoMock package.
5 | package lattice
6 |
7 | import (
8 | context "context"
9 | reflect "reflect"
10 |
11 | lattice "github.com/aws/aws-application-networking-k8s/pkg/model/lattice"
12 | vpclattice "github.com/aws/aws-sdk-go/service/vpclattice"
13 | gomock "github.com/golang/mock/gomock"
14 | )
15 |
16 | // MockTargetsManager is a mock of TargetsManager interface.
17 | type MockTargetsManager struct {
18 | ctrl *gomock.Controller
19 | recorder *MockTargetsManagerMockRecorder
20 | }
21 |
22 | // MockTargetsManagerMockRecorder is the mock recorder for MockTargetsManager.
23 | type MockTargetsManagerMockRecorder struct {
24 | mock *MockTargetsManager
25 | }
26 |
27 | // NewMockTargetsManager creates a new mock instance.
28 | func NewMockTargetsManager(ctrl *gomock.Controller) *MockTargetsManager {
29 | mock := &MockTargetsManager{ctrl: ctrl}
30 | mock.recorder = &MockTargetsManagerMockRecorder{mock}
31 | return mock
32 | }
33 |
34 | // EXPECT returns an object that allows the caller to indicate expected use.
35 | func (m *MockTargetsManager) EXPECT() *MockTargetsManagerMockRecorder {
36 | return m.recorder
37 | }
38 |
39 | // List mocks base method.
40 | func (m *MockTargetsManager) List(arg0 context.Context, arg1 *lattice.TargetGroup) ([]*vpclattice.TargetSummary, error) {
41 | m.ctrl.T.Helper()
42 | ret := m.ctrl.Call(m, "List", arg0, arg1)
43 | ret0, _ := ret[0].([]*vpclattice.TargetSummary)
44 | ret1, _ := ret[1].(error)
45 | return ret0, ret1
46 | }
47 |
48 | // List indicates an expected call of List.
49 | func (mr *MockTargetsManagerMockRecorder) List(arg0, arg1 interface{}) *gomock.Call {
50 | mr.mock.ctrl.T.Helper()
51 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockTargetsManager)(nil).List), arg0, arg1)
52 | }
53 |
54 | // Update mocks base method.
55 | func (m *MockTargetsManager) Update(arg0 context.Context, arg1 *lattice.Targets, arg2 *lattice.TargetGroup) error {
56 | m.ctrl.T.Helper()
57 | ret := m.ctrl.Call(m, "Update", arg0, arg1, arg2)
58 | ret0, _ := ret[0].(error)
59 | return ret0
60 | }
61 |
62 | // Update indicates an expected call of Update.
63 | func (mr *MockTargetsManagerMockRecorder) Update(arg0, arg1, arg2 interface{}) *gomock.Call {
64 | mr.mock.ctrl.T.Helper()
65 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockTargetsManager)(nil).Update), arg0, arg1, arg2)
66 | }
67 |
--------------------------------------------------------------------------------
/pkg/deploy/stack_deployer_test.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 | "testing"
8 | "time"
9 |
10 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestTgGc(t *testing.T) {
15 |
16 | type test struct {
17 | name string
18 | gcFn TgGcCycleFn
19 | }
20 |
21 | tests := []test{
22 | {
23 | name: "empty cycle",
24 | gcFn: func(context.Context) (TgGcResult, error) { return TgGcResult{}, nil },
25 | },
26 | {
27 | name: "cycle with results",
28 | gcFn: func(context.Context) (TgGcResult, error) {
29 | return TgGcResult{
30 | att: 10,
31 | succ: 10,
32 | duration: time.Second,
33 | }, nil
34 | },
35 | },
36 | {
37 | name: "cycle panic",
38 | gcFn: func(context.Context) (TgGcResult, error) { panic("") },
39 | },
40 | {
41 | name: "cycle error",
42 | gcFn: func(context.Context) (TgGcResult, error) { return TgGcResult{}, errors.New("") },
43 | },
44 | }
45 |
46 | nCycles := 10 // run each test at least 10 cycles
47 |
48 | for _, tt := range tests {
49 | t.Run(tt.name, func(t *testing.T) {
50 | ctx, cancel := context.WithCancel(context.Background())
51 | n := 0
52 | f := func(ctx context.Context) (TgGcResult, error) {
53 | defer func() {
54 | n += 1
55 | if n >= nCycles {
56 | cancel()
57 | }
58 | }()
59 | return tt.gcFn(ctx)
60 | }
61 | ivl := time.Millisecond * 10
62 | tgGc := &TgGc{
63 | log: gwlog.FallbackLogger,
64 | ctx: ctx,
65 | ivl: ivl,
66 | cycleFn: f,
67 | }
68 | tgGc.start()
69 | time.Sleep(ivl * (time.Duration(nCycles) + 2)) // sleep enough cycles to terminate
70 | assert.Equal(t, nCycles, n, fmt.Sprintf("should run only %d cycles", nCycles))
71 | assert.True(t, tgGc.isDone.Load(), "gc must terminate")
72 | })
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/deploy/stack_marshaller.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
6 | )
7 |
8 | // StackMarshaller will marshall a resource stack into JSON.
9 | type StackMarshaller interface {
10 | Marshal(stack core.Stack) (string, error)
11 | }
12 |
13 | func NewDefaultStackMarshaller() *defaultStackMarshaller {
14 | return &defaultStackMarshaller{}
15 | }
16 |
17 | var _ StackMarshaller = &defaultStackMarshaller{}
18 |
19 | type defaultStackMarshaller struct{}
20 |
21 | func (m *defaultStackMarshaller) Marshal(stack core.Stack) (string, error) {
22 | builder := NewStackSchemaBuilder(stack.StackID())
23 | if err := stack.TopologicalTraversal(builder); err != nil {
24 | return "", err
25 | }
26 | stackSchema := builder.Build()
27 | payload, err := json.Marshal(stackSchema)
28 | if err != nil {
29 | return "", err
30 | }
31 | return string(payload), nil
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/deploy/stack_schema_builder.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | coremodel "github.com/aws/aws-application-networking-k8s/pkg/model/core"
5 | )
6 |
7 | // StackSchema represents the JSON model for stack.
8 | type StackSchema struct {
9 | // Stack's ID
10 | ID string `json:"id"`
11 |
12 | // all resources within stack.
13 | Resources map[string]map[string]interface{} `json:"resources"`
14 | }
15 |
16 | // NewStackSchemaBuilder constructs new stackSchemaBuilder.
17 | func NewStackSchemaBuilder(stackID coremodel.StackID) *stackSchemaBuilder {
18 | return &stackSchemaBuilder{
19 | stackID: stackID,
20 | resources: make(map[string]map[string]interface{}),
21 | }
22 | }
23 |
24 | var _ coremodel.ResourceVisitor = &stackSchemaBuilder{}
25 |
26 | type stackSchemaBuilder struct {
27 | stackID coremodel.StackID
28 | resources map[string]map[string]interface{}
29 | }
30 |
31 | // Visit will visit a resource.
32 | func (b *stackSchemaBuilder) Visit(res coremodel.Resource) error {
33 | if _, ok := b.resources[res.Type()]; !ok {
34 | b.resources[res.Type()] = make(map[string]interface{})
35 | }
36 | b.resources[res.Type()][res.ID()] = res
37 | return nil
38 | }
39 |
40 | // Build will build StackSchema based on resources visited.
41 | func (b *stackSchemaBuilder) Build() StackSchema {
42 | return StackSchema{
43 | ID: b.stackID.String(),
44 | Resources: b.resources,
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/gateway/model_build_lattice_service_mock.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/aws/aws-application-networking-k8s/pkg/gateway (interfaces: LatticeServiceBuilder)
3 |
4 | // Package gateway is a generated GoMock package.
5 | package gateway
6 |
7 | import (
8 | context "context"
9 | reflect "reflect"
10 |
11 | core "github.com/aws/aws-application-networking-k8s/pkg/model/core"
12 | gomock "github.com/golang/mock/gomock"
13 | )
14 |
15 | // MockLatticeServiceBuilder is a mock of LatticeServiceBuilder interface.
16 | type MockLatticeServiceBuilder struct {
17 | ctrl *gomock.Controller
18 | recorder *MockLatticeServiceBuilderMockRecorder
19 | }
20 |
21 | // MockLatticeServiceBuilderMockRecorder is the mock recorder for MockLatticeServiceBuilder.
22 | type MockLatticeServiceBuilderMockRecorder struct {
23 | mock *MockLatticeServiceBuilder
24 | }
25 |
26 | // NewMockLatticeServiceBuilder creates a new mock instance.
27 | func NewMockLatticeServiceBuilder(ctrl *gomock.Controller) *MockLatticeServiceBuilder {
28 | mock := &MockLatticeServiceBuilder{ctrl: ctrl}
29 | mock.recorder = &MockLatticeServiceBuilderMockRecorder{mock}
30 | return mock
31 | }
32 |
33 | // EXPECT returns an object that allows the caller to indicate expected use.
34 | func (m *MockLatticeServiceBuilder) EXPECT() *MockLatticeServiceBuilderMockRecorder {
35 | return m.recorder
36 | }
37 |
38 | // Build mocks base method.
39 | func (m *MockLatticeServiceBuilder) Build(arg0 context.Context, arg1 core.Route) (core.Stack, error) {
40 | m.ctrl.T.Helper()
41 | ret := m.ctrl.Call(m, "Build", arg0, arg1)
42 | ret0, _ := ret[0].(core.Stack)
43 | ret1, _ := ret[1].(error)
44 | return ret0, ret1
45 | }
46 |
47 | // Build indicates an expected call of Build.
48 | func (mr *MockLatticeServiceBuilderMockRecorder) Build(arg0, arg1 interface{}) *gomock.Call {
49 | mr.mock.ctrl.T.Helper()
50 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Build", reflect.TypeOf((*MockLatticeServiceBuilder)(nil).Build), arg0, arg1)
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/k8s/events.go:
--------------------------------------------------------------------------------
1 | package k8s
2 |
3 | const (
4 | // Generic events
5 | ReconcilingEvent = "Reconciling"
6 | ReconciledEvent = "Reconciled"
7 | FailedReconcileEvent = "FailedReconcile"
8 |
9 | // Gateway events
10 | GatewayEventReasonFailedAddFinalizer = "FailedAddFinalizer"
11 | GatewayEventReasonFailedBuildModel = "FailedBuildModel"
12 | GatewayEventReasonFailedDeployModel = "FailedDeployModel"
13 |
14 | // Route events
15 | RouteEventReasonReconcile = "Reconcile"
16 | RouteEventReasonDeploySucceed = "DeploySucceed"
17 | RouteEventReasonFailedAddFinalizer = "FailedAddFinalizer"
18 | RouteEventReasonFailedBuildModel = "FailedBuildModel"
19 | RouteEventReasonFailedDeployModel = "FailedDeployModel"
20 | RouteEventReasonRetryReconcile = "Retry-Reconcile"
21 |
22 | // Service events
23 | ServiceEventReasonFailedAddFinalizer = "FailedAddFinalizer"
24 | ServiceEventReasonFailedBuildModel = "FailedBuildModel"
25 | ServiceEventReasonFailedDeployModel = "FailedDeployModel"
26 |
27 | // ServiceExport events
28 | ServiceExportEventReasonFailedAddFinalizer = "FailedAddFinalizer"
29 | ServiceExportEventReasonFailedBuildModel = "FailedBuildModel"
30 | ServiceExportEventReasonFailedDeployModel = "FailedDeployModel"
31 |
32 | // ServiceImport events
33 | ServiceImportEventReasonFailedAddFinalizer = "FailedAddFinalizer"
34 | ServiceImportEventReasonFailedBuildModel = "FailedBuildModel"
35 | ServiceImportEventReasonFailedDeployModel = "FailedDeployModel"
36 | )
37 |
--------------------------------------------------------------------------------
/pkg/k8s/finalizer.go:
--------------------------------------------------------------------------------
1 | package k8s
2 |
3 | import (
4 | "context"
5 |
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | "k8s.io/client-go/util/retry"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 | "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
10 | )
11 |
12 | //go:generate mockgen -destination finalizer_mock.go -package k8s github.com/aws/aws-application-networking-k8s/pkg/k8s FinalizerManager
13 |
14 | type FinalizerManager interface {
15 | AddFinalizers(ctx context.Context, object client.Object, finalizers ...string) error
16 | RemoveFinalizers(ctx context.Context, object client.Object, finalizers ...string) error
17 | }
18 |
19 | func NewDefaultFinalizerManager(k8sClient client.Client) FinalizerManager {
20 | return &defaultFinalizerManager{
21 | k8sClient: k8sClient,
22 | }
23 | }
24 |
25 | type defaultFinalizerManager struct {
26 | k8sClient client.Client
27 | }
28 |
29 | func (m *defaultFinalizerManager) AddFinalizers(ctx context.Context, obj client.Object, finalizers ...string) error {
30 | return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
31 | if err := m.k8sClient.Get(ctx, NamespacedName(obj), obj); err != nil {
32 | return err
33 | }
34 |
35 | oldObj := obj.DeepCopyObject().(client.Object)
36 | needsUpdate := false
37 | for _, finalizer := range finalizers {
38 | if !HasFinalizer(obj, finalizer) {
39 | controllerutil.AddFinalizer(obj, finalizer)
40 | needsUpdate = true
41 | }
42 | }
43 | if !needsUpdate {
44 | return nil
45 | }
46 | return m.k8sClient.Patch(ctx, obj, client.MergeFromWithOptions(oldObj, client.MergeFromWithOptimisticLock{}))
47 | })
48 | }
49 |
50 | func (m *defaultFinalizerManager) RemoveFinalizers(ctx context.Context, obj client.Object, finalizers ...string) error {
51 | return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
52 | if err := m.k8sClient.Get(ctx, NamespacedName(obj), obj); err != nil {
53 | return err
54 | }
55 |
56 | oldObj := obj.DeepCopyObject().(client.Object)
57 | needsUpdate := false
58 | for _, finalizer := range finalizers {
59 | if HasFinalizer(obj, finalizer) {
60 | controllerutil.RemoveFinalizer(obj, finalizer)
61 | needsUpdate = true
62 | }
63 | }
64 | if !needsUpdate {
65 | return nil
66 | }
67 | return m.k8sClient.Patch(ctx, obj, client.MergeFromWithOptions(oldObj, client.MergeFromWithOptimisticLock{}))
68 | })
69 | }
70 |
71 | // HasFinalizer tests whether k8s object has specified finalizer
72 | func HasFinalizer(obj metav1.Object, finalizer string) bool {
73 | f := obj.GetFinalizers()
74 | for _, e := range f {
75 | if e == finalizer {
76 | return true
77 | }
78 | }
79 | return false
80 | }
81 |
--------------------------------------------------------------------------------
/pkg/k8s/policyhelper/kind.go:
--------------------------------------------------------------------------------
1 | package policyhelper
2 |
3 | import (
4 | corev1 "k8s.io/api/core/v1"
5 | "sigs.k8s.io/controller-runtime/pkg/client"
6 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
7 | gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
8 |
9 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
10 | )
11 |
12 | type GroupKind struct {
13 | Group string
14 | Kind string
15 | }
16 |
17 | func ObjToGroupKind(obj client.Object) GroupKind {
18 | switch obj.(type) {
19 | case *gwv1.Gateway:
20 | return GroupKind{gwv1.GroupName, "Gateway"}
21 | case *gwv1.HTTPRoute:
22 | return GroupKind{gwv1.GroupName, "HTTPRoute"}
23 | case *gwv1.GRPCRoute:
24 | return GroupKind{gwv1alpha2.GroupName, "GRPCRoute"}
25 | case *gwv1alpha2.TCPRoute:
26 | return GroupKind{gwv1alpha2.GroupName, "TCPRoute"}
27 | case *anv1alpha1.ServiceExport:
28 | return GroupKind{anv1alpha1.GroupName, "ServiceExport"}
29 | case *corev1.Service:
30 | return GroupKind{corev1.GroupName, "Service"}
31 | default:
32 | return GroupKind{}
33 | }
34 | }
35 |
36 | func TargetRefGroupKind(tr *TargetRef) GroupKind {
37 | return GroupKind{
38 | Group: string(tr.Group),
39 | Kind: string(tr.Kind),
40 | }
41 | }
42 |
43 | func GroupKindToObj(gk GroupKind) (client.Object, bool) {
44 | switch gk {
45 | case GroupKind{gwv1.GroupName, "Gateway"}:
46 | return &gwv1.Gateway{}, true
47 | case GroupKind{gwv1.GroupName, "HTTPRoute"}:
48 | return &gwv1.HTTPRoute{}, true
49 | case GroupKind{gwv1alpha2.GroupName, "GRPCRoute"}:
50 | return &gwv1.GRPCRoute{}, true
51 | case GroupKind{gwv1alpha2.GroupName, "TCPRoute"}:
52 | return &gwv1alpha2.TCPRoute{}, true
53 | case GroupKind{corev1.GroupName, "Service"}:
54 | return &corev1.Service{}, true
55 | case GroupKind{anv1alpha1.GroupName, "ServiceExport"}:
56 | return &anv1alpha1.ServiceExport{}, true
57 | default:
58 | return nil, false
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/k8s/policyhelper/kind_test.go:
--------------------------------------------------------------------------------
1 | package policyhelper
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | corev1 "k8s.io/api/core/v1"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
10 | )
11 |
12 | func TestGroupKind(t *testing.T) {
13 | type Test struct {
14 | obj client.Object
15 | kind GroupKind
16 | }
17 |
18 | tests := []Test{
19 | {&gwv1.Gateway{}, GroupKind{Group: gwv1.GroupName, Kind: "Gateway"}},
20 | {&gwv1.HTTPRoute{}, GroupKind{Group: gwv1.GroupName, Kind: "HTTPRoute"}},
21 | {&gwv1.GRPCRoute{}, GroupKind{Group: gwv1.GroupName, Kind: "GRPCRoute"}},
22 | {&corev1.Service{}, GroupKind{Group: corev1.GroupName, Kind: "Service"}},
23 | }
24 |
25 | t.Run("obj to kind", func(t *testing.T) {
26 | for _, tt := range tests {
27 | assert.Equal(t, ObjToGroupKind(tt.obj), tt.kind)
28 | }
29 | })
30 |
31 | t.Run("kind to obj", func(t *testing.T) {
32 | for _, tt := range tests {
33 | kind, _ := GroupKindToObj(tt.kind)
34 | assert.Equal(t, kind, tt.obj)
35 | }
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/k8s/policyhelper/policy_test.go:
--------------------------------------------------------------------------------
1 | package policyhelper
2 |
3 | import (
4 | "testing"
5 |
6 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
7 | "github.com/stretchr/testify/assert"
8 | "sigs.k8s.io/controller-runtime/pkg/client"
9 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
10 | )
11 |
12 | func TestPolicyClient(t *testing.T) {
13 | type iap = anv1alpha1.IAMAuthPolicy
14 | type iapl = anv1alpha1.IAMAuthPolicyList
15 |
16 | t.Run("new list and policy", func(t *testing.T) {
17 | c := newK8sPolicyClient[iap, iapl](nil)
18 | assert.NotNil(t, c.newPolicy())
19 | assert.NotNil(t, c.newList())
20 | })
21 | }
22 |
23 | func TestPolicyHandler(t *testing.T) {
24 | type iap = anv1alpha1.IAMAuthPolicy
25 | type iapl = anv1alpha1.IAMAuthPolicyList
26 |
27 | phcfg := PolicyHandlerConfig{}
28 | _ = NewPolicyHandler[iap, iapl](phcfg)
29 | }
30 |
31 | func TestGroupKindSet(t *testing.T) {
32 | objs := []client.Object{&gwv1.Gateway{}, &gwv1.HTTPRoute{}, &gwv1.GRPCRoute{}}
33 | gks := NewGroupKindSet(objs...)
34 | assert.True(t, gks.Contains(GroupKind{gwv1.GroupName, "Gateway"}))
35 | assert.True(t, gks.Contains(GroupKind{gwv1.GroupName, "HTTPRoute"}))
36 | assert.True(t, gks.Contains(GroupKind{gwv1.GroupName, "GRPCRoute"}))
37 | }
38 |
--------------------------------------------------------------------------------
/pkg/model/core/fake_resource.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 | )
8 |
9 | var _ Resource = &FakeResource{}
10 |
11 | func NewFakeResource(stack Stack, resType string, id string, spec FakeResourceSpec, status *FakeResourceStatus) *FakeResource {
12 | r := &FakeResource{
13 | ResourceMeta: NewResourceMeta(stack, resType, id),
14 | Spec: spec,
15 | Status: status,
16 | }
17 | stack.AddResource(r)
18 | return r
19 | }
20 |
21 | func (r *FakeResource) FieldB() StringToken {
22 | return NewResourceFieldStringToken(r, "status/fieldB",
23 | func(ctx context.Context, res Resource, fieldPath string) (s string, err error) {
24 | r := res.(*FakeResource)
25 | if r.Status == nil {
26 | return "", errors.Errorf("FakeResource is not fulfilled yet: %v", r.ID())
27 | }
28 | return r.Status.FieldB, nil
29 | },
30 | )
31 | }
32 |
33 | type FakeResource struct {
34 | ResourceMeta `json:"-"`
35 |
36 | Spec FakeResourceSpec `json:"spec"`
37 | Status *FakeResourceStatus `json:"status,omitempty"`
38 | }
39 |
40 | type FakeResourceSpec struct {
41 | FieldA []StringToken `json:"fieldA"`
42 | }
43 |
44 | type FakeResourceStatus struct {
45 | FieldB string `json:"fieldB"`
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/model/core/graph/resource_graph.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | import "reflect"
4 |
5 | // unique ID for a resource.
6 | type ResourceUID struct {
7 | ResType reflect.Type
8 | ResID string
9 | }
10 |
11 | // ResourceGraph is an abstraction of resource DAG.
12 | type ResourceGraph interface {
13 | // Add a node into ResourceGraph.
14 | AddNode(node ResourceUID)
15 |
16 | // Add a edge into ResourceGraph, where dstNode depends on srcNode.
17 | AddEdge(srcNode ResourceUID, dstNode ResourceUID)
18 |
19 | // Nodes returns all nodes in ResourceGraph.
20 | Nodes() []ResourceUID
21 |
22 | // OutEdgeNodes returns all nodes that depends on this node.
23 | OutEdgeNodes(node ResourceUID) []ResourceUID
24 | }
25 |
26 | // NewDefaultResourceGraph constructs new defaultResourceGraph.
27 | func NewDefaultResourceGraph() *defaultResourceGraph {
28 | return &defaultResourceGraph{
29 | nodes: nil,
30 | outEdges: make(map[ResourceUID][]ResourceUID),
31 | }
32 | }
33 |
34 | var _ ResourceGraph = &defaultResourceGraph{}
35 |
36 | // defaultResourceGraph is the default implementation for ResourceGraph.
37 | type defaultResourceGraph struct {
38 | nodes []ResourceUID
39 | outEdges map[ResourceUID][]ResourceUID
40 | }
41 |
42 | // Add a node into ResourceGraph.
43 | func (g *defaultResourceGraph) AddNode(node ResourceUID) {
44 | g.nodes = append(g.nodes, node)
45 | }
46 |
47 | // Add a edge into ResourceGraph, where dstNode depends on srcNode.
48 | func (g *defaultResourceGraph) AddEdge(srcNode ResourceUID, dstNode ResourceUID) {
49 | g.outEdges[srcNode] = append(g.outEdges[srcNode], dstNode)
50 | }
51 |
52 | // Nodes returns all nodes in ResourceGraph.
53 | func (g *defaultResourceGraph) Nodes() []ResourceUID {
54 | return g.nodes
55 | }
56 |
57 | // OutEdgeNodes returns all nodes that depends on this node.
58 | func (g *defaultResourceGraph) OutEdgeNodes(node ResourceUID) []ResourceUID {
59 | return g.outEdges[node]
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/model/core/graph/typological_traversal.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | import (
4 | "github.com/pkg/errors"
5 | )
6 |
7 | // TopologicalTraversal will traversal nodes in typological order.
8 | // @TODO: change this traversal to be parallel.
9 | func TopologicalTraversal(graph ResourceGraph, visitFunc func(uid ResourceUID) error) error {
10 | nodes := graph.Nodes()
11 | indegreeByNode := make(map[ResourceUID]int, len(nodes))
12 | for _, node := range nodes {
13 | if _, ok := indegreeByNode[node]; !ok {
14 | indegreeByNode[node] = 0
15 | }
16 | for _, outEdgeNode := range graph.OutEdgeNodes(node) {
17 | indegreeByNode[outEdgeNode]++
18 | }
19 |
20 | }
21 |
22 | var queue []ResourceUID
23 | for node, indegree := range indegreeByNode {
24 | if indegree == 0 {
25 | queue = append(queue, node)
26 | }
27 | }
28 |
29 | for len(queue) > 0 {
30 | node := queue[len(queue)-1]
31 | queue = queue[:len(queue)-1]
32 | if err := visitFunc(node); err != nil {
33 | return err
34 | }
35 |
36 | for _, outEdgeNode := range graph.OutEdgeNodes(node) {
37 | indegreeByNode[outEdgeNode]--
38 | if indegreeByNode[outEdgeNode] == 0 {
39 | queue = append(queue, outEdgeNode)
40 | }
41 | }
42 | }
43 |
44 | for _, indegree := range indegreeByNode {
45 | if indegree > 0 {
46 | return errors.New("ResourceGraph is not a DAG")
47 | }
48 | }
49 | return nil
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/model/core/policy.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | apimachineryv1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 | "k8s.io/apimachinery/pkg/types"
6 | "sigs.k8s.io/controller-runtime/pkg/client"
7 | gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
8 | )
9 |
10 | type Policy interface {
11 | client.Object
12 | GetNamespacedName() types.NamespacedName
13 | GetTargetRef() *gwv1alpha2.NamespacedPolicyTargetReference
14 | GetStatusConditions() []apimachineryv1.Condition
15 | SetStatusConditions(conditions []apimachineryv1.Condition)
16 | }
17 |
18 | type PolicyList interface {
19 | GetItems() []Policy
20 | }
21 |
--------------------------------------------------------------------------------
/pkg/model/core/resource.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | // Resource represents a deployment unit.
4 | type Resource interface {
5 | // resource's stack.
6 | Stack() Stack
7 |
8 | // resource's Type.
9 | Type() string
10 |
11 | // resource's ID within stack.
12 | ID() string
13 | }
14 |
15 | // NewResourceMeta constructs new resource metadata.
16 | func NewResourceMeta(stack Stack, resType string, id string) ResourceMeta {
17 | return ResourceMeta{
18 | stack: stack,
19 | resType: resType,
20 | id: id,
21 | }
22 | }
23 |
24 | // Metadata for all resources.
25 | type ResourceMeta struct {
26 | stack Stack
27 | resType string
28 | id string
29 | }
30 |
31 | func (m *ResourceMeta) Stack() Stack {
32 | return m.stack
33 | }
34 |
35 | func (m *ResourceMeta) Type() string {
36 | return m.resType
37 | }
38 |
39 | func (m *ResourceMeta) ID() string {
40 | return m.id
41 | }
42 |
43 | // ResourceVisitor represents a functor that can operate on a resource.
44 | type ResourceVisitor interface {
45 | Visit(res Resource) error
46 | }
47 |
48 | type EventType string
49 |
50 | const (
51 | CreateEvent EventType = "Create"
52 | UpdateEvent EventType = "Update"
53 | DeleteEvent EventType = "Delete"
54 | )
55 |
--------------------------------------------------------------------------------
/pkg/model/core/stack_id.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "k8s.io/apimachinery/pkg/types"
6 | )
7 |
8 | // stackId is the identifier of a stack, it must be compatible with Kubernetes namespaced name.
9 | type StackID types.NamespacedName
10 |
11 | // String returns the string representation of a StackID.
12 | // It will be used as AWS resource tags for resources provisioned for this stack.
13 | func (stackID StackID) String() string {
14 | if stackID.Namespace == "" {
15 | return stackID.Name
16 | }
17 | return fmt.Sprintf("%s/%s", stackID.Namespace, stackID.Name)
18 | }
19 |
--------------------------------------------------------------------------------
/pkg/model/core/token_types.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | )
7 |
8 | // Token represent a value that can be resolved at resolution time.
9 | type Token interface {
10 | // token's value resolution may depends on 0 or more Resources.
11 | Dependencies() []Resource
12 | }
13 |
14 | // StringToken represent a string value that can be resolved at resolution time.
15 | type StringToken interface {
16 | Token
17 | Resolve(ctx context.Context) (string, error)
18 | }
19 |
20 | var _ StringToken = LiteralStringToken("")
21 |
22 | // LiteralStringToken represents a literal string value.
23 | type LiteralStringToken string
24 |
25 | func (t LiteralStringToken) Resolve(ctx context.Context) (string, error) {
26 | return string(t), nil
27 | }
28 |
29 | func (t LiteralStringToken) Dependencies() []Resource {
30 | return nil
31 | }
32 |
33 | // NewResourceFieldStringToken constructs new ResourceFieldStringToken.
34 | // @TODO: ideally the resolverFunc can be a shared implementation which dump Resource as json and obtain the fieldPath.
35 | func NewResourceFieldStringToken(res Resource, fieldPath string,
36 | resolverFunc func(ctx context.Context, res Resource, fieldPath string) (string, error)) *ResourceFieldStringToken {
37 | return &ResourceFieldStringToken{
38 | res: res,
39 | fieldPath: fieldPath,
40 | resolveFunc: resolverFunc,
41 | }
42 | }
43 |
44 | var _ StringToken = &ResourceFieldStringToken{}
45 |
46 | type ResourceFieldStringToken struct {
47 | res Resource
48 | fieldPath string
49 | resolveFunc func(ctx context.Context, res Resource, fieldPath string) (string, error)
50 | }
51 |
52 | func (t *ResourceFieldStringToken) Resolve(ctx context.Context) (string, error) {
53 | return t.resolveFunc(ctx, t.res, t.fieldPath)
54 | }
55 |
56 | func (t *ResourceFieldStringToken) Dependencies() []Resource {
57 | return []Resource{t.res}
58 | }
59 |
60 | func (t *ResourceFieldStringToken) MarshalJSON() ([]byte, error) {
61 | payload := fmt.Sprintf(`{"$ref": "#/resources/%v/%v/%v"}`, t.res.Type(), t.res.ID(), t.fieldPath)
62 | return []byte(payload), nil
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/model/lattice/accesslogsubscription.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "fmt"
5 |
6 | "k8s.io/apimachinery/pkg/types"
7 |
8 | "github.com/aws/aws-application-networking-k8s/pkg/aws"
9 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
10 | )
11 |
12 | const AccessLogPolicyTagKey = aws.TagBase + "AccessLogPolicy"
13 |
14 | type SourceType string
15 |
16 | const (
17 | ServiceNetworkSourceType SourceType = "ServiceNetwork"
18 | ServiceSourceType SourceType = "Service"
19 | )
20 |
21 | type AccessLogSubscription struct {
22 | core.ResourceMeta `json:"-"`
23 | Spec AccessLogSubscriptionSpec `json:"spec"`
24 | Status *AccessLogSubscriptionStatus `json:"status,omitempty"`
25 | }
26 |
27 | type AccessLogSubscriptionSpec struct {
28 | SourceType SourceType
29 | SourceName string
30 | DestinationArn string
31 | ALPNamespacedName types.NamespacedName
32 | EventType core.EventType
33 | }
34 |
35 | type AccessLogSubscriptionStatus struct {
36 | Arn string `json:"arn"`
37 | }
38 |
39 | func NewAccessLogSubscription(
40 | stack core.Stack,
41 | spec AccessLogSubscriptionSpec,
42 | status *AccessLogSubscriptionStatus,
43 | ) *AccessLogSubscription {
44 | id := fmt.Sprintf("%s-%s-%s", spec.SourceType, spec.SourceName, spec.DestinationArn)
45 | return &AccessLogSubscription{
46 | ResourceMeta: core.NewResourceMeta(stack, "AWS::VPCServiceNetwork::AccessLogSubscription", id),
47 | Spec: spec,
48 | Status: status,
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/model/lattice/iamauthpolicy.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "fmt"
5 |
6 | anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
7 | "github.com/aws/aws-application-networking-k8s/pkg/utils"
8 | )
9 |
10 | type IAMAuthPolicy struct {
11 | Type string
12 | Name string
13 | ResourceId string
14 | Policy string
15 | }
16 |
17 | type IAMAuthPolicyStatus struct {
18 | ResourceId string
19 | }
20 |
21 | func NewIAMAuthPolicy(k8sPolicy *anv1alpha1.IAMAuthPolicy) IAMAuthPolicy {
22 | kind := k8sPolicy.Spec.TargetRef.Kind
23 | policy := k8sPolicy.Spec.Policy
24 | switch kind {
25 | case "Gateway":
26 | return IAMAuthPolicy{
27 | Type: ServiceNetworkType,
28 | Name: string(k8sPolicy.Spec.TargetRef.Name),
29 | Policy: policy,
30 | }
31 | case "HTTPRoute", "GRPCRoute":
32 | return IAMAuthPolicy{
33 | Type: ServiceType,
34 | Name: utils.LatticeServiceName(string(k8sPolicy.Spec.TargetRef.Name), k8sPolicy.Namespace),
35 | Policy: policy,
36 | }
37 | default:
38 | panic(fmt.Sprintf("unexpected targetRef, Kind=%s", kind))
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/model/lattice/service.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "github.com/aws/aws-application-networking-k8s/pkg/aws/services"
5 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
6 | "github.com/aws/aws-application-networking-k8s/pkg/utils"
7 | )
8 |
9 | type Service struct {
10 | core.ResourceMeta `json:"-"`
11 | Spec ServiceSpec `json:"spec"`
12 | Status *ServiceStatus `json:"status,omitempty"`
13 | IsDeleted bool `json:"isdeleted"`
14 | }
15 |
16 | type ServiceSpec struct {
17 | ServiceTagFields
18 | ServiceNetworkNames []string `json:"servicenetworkhnames"`
19 | CustomerDomainName string `json:"customerdomainname"`
20 | CustomerCertARN string `json:"customercertarn"`
21 | }
22 |
23 | type ServiceStatus struct {
24 | Arn string `json:"arn"`
25 | Id string `json:"id"`
26 | Dns string `json:"dns"`
27 | }
28 |
29 | type ServiceTagFields struct {
30 | RouteName string
31 | RouteNamespace string
32 | RouteType core.RouteType
33 | }
34 |
35 | func ServiceTagFieldsFromTags(tags map[string]*string) ServiceTagFields {
36 | return ServiceTagFields{
37 | RouteName: getMapValue(tags, K8SRouteNameKey),
38 | RouteNamespace: getMapValue(tags, K8SRouteNamespaceKey),
39 | RouteType: core.RouteType(getMapValue(tags, K8SRouteTypeKey)),
40 | }
41 | }
42 |
43 | func (t *ServiceTagFields) ToTags() services.Tags {
44 | rt := string(t.RouteType)
45 | return services.Tags{
46 | K8SRouteNameKey: &t.RouteName,
47 | K8SRouteNamespaceKey: &t.RouteNamespace,
48 | K8SRouteTypeKey: &rt,
49 | }
50 | }
51 |
52 | func NewLatticeService(stack core.Stack, spec ServiceSpec) (*Service, error) {
53 | id := spec.LatticeServiceName()
54 |
55 | service := &Service{
56 | ResourceMeta: core.NewResourceMeta(stack, "AWS::VPCServiceNetwork::Service", id),
57 | Spec: spec,
58 | Status: nil,
59 | }
60 |
61 | err := stack.AddResource(service)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | return service, nil
67 | }
68 |
69 | func (s *Service) LatticeServiceName() string {
70 | return s.Spec.LatticeServiceName()
71 | }
72 |
73 | func (s *ServiceSpec) LatticeServiceName() string {
74 | return utils.LatticeServiceName(s.RouteName, s.RouteNamespace)
75 | }
76 |
--------------------------------------------------------------------------------
/pkg/model/lattice/servicenetwork.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
5 | )
6 |
7 | const (
8 | K8SServiceNetworkOwnedByVPC = "K8SServiceNetworkOwnedByVPC"
9 | K8SServiceOwnedByVPC = "K8SServiceOwnedByVPC"
10 | )
11 |
12 | type ServiceNetwork struct {
13 | core.ResourceMeta `json:"-"`
14 | Spec ServiceNetworkSpec `json:"spec"`
15 | Status *ServiceNetworkStatus `json:"status,omitempty"`
16 | }
17 |
18 | type ServiceNetworkSpec struct {
19 | // The name of the ServiceNetwork
20 | Name string `json:"name"`
21 | Namespace string `json:"namespace"`
22 | Account string `json:"account"`
23 | SecurityGroupIds []*string `json:"securityGroupIds"`
24 | AssociateToVPC bool
25 | IsDeleted bool
26 | }
27 |
28 | type ServiceNetworkStatus struct {
29 | ServiceNetworkARN string `json:"servicenetworkARN"`
30 | ServiceNetworkID string `json:"servicenetworkID"`
31 | SnvaSecurityGroupIds []*string `json:"securityGroupIds"`
32 | }
33 |
34 | func NewServiceNetwork(stack core.Stack, id string, spec ServiceNetworkSpec) *ServiceNetwork {
35 |
36 | servicenetwork := &ServiceNetwork{
37 | //TODO right name
38 | ResourceMeta: core.NewResourceMeta(stack, "AWS::VPCServiceNetwork::ServiceNetwork", id),
39 | Spec: spec,
40 | Status: nil,
41 | }
42 |
43 | stack.AddResource(servicenetwork)
44 | // TODO: servicenetwork.registerDependencies(stack)
45 |
46 | return servicenetwork
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/model/lattice/targets.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | import (
4 | "github.com/aws/aws-application-networking-k8s/pkg/model/core"
5 | "k8s.io/apimachinery/pkg/types"
6 | )
7 |
8 | type Targets struct {
9 | core.ResourceMeta `json:"-"`
10 | Spec TargetsSpec `json:"spec"`
11 | }
12 |
13 | // unlike target groups, which can reference a service export, targets
14 | // are always sourced from the local cluster. When we update targets,
15 | // we find all the target groups linked to the specific service
16 | type TargetsSpec struct {
17 | StackTargetGroupId string `json:"stacktargetgroupid"`
18 | TargetList []Target `json:"targetlist"`
19 | }
20 |
21 | type Target struct {
22 | TargetIP string `json:"targetip"`
23 | Port int64 `json:"port"`
24 | Ready bool `json:"ready"`
25 | TargetRef types.NamespacedName
26 | }
27 |
28 | func NewTargets(stack core.Stack, spec TargetsSpec) (*Targets, error) {
29 | id, err := core.IdFromHash(spec)
30 | if err != nil {
31 | return nil, err
32 | }
33 | targets := &Targets{
34 | ResourceMeta: core.NewResourceMeta(stack, "AWS:VPCServiceNetwork::Targets", id),
35 | Spec: spec,
36 | }
37 |
38 | stack.AddResource(targets)
39 |
40 | return targets, nil
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/model/lattice/types.go:
--------------------------------------------------------------------------------
1 | package lattice
2 |
3 | const (
4 | ServiceNetworkType = "ServiceNetwork"
5 | ServiceType = "Service"
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/runtime/errors.go:
--------------------------------------------------------------------------------
1 | package runtime
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "time"
7 |
8 | "github.com/aws/aws-application-networking-k8s/pkg/deploy/lattice"
9 | )
10 |
11 | type RetryError error
12 |
13 | func NewRetryError() RetryError {
14 | return RetryError(errors.New(lattice.LATTICE_RETRY))
15 | }
16 |
17 | // NewRequeueNeeded constructs new RequeueError to
18 | // instruct controller-runtime to requeue the processing item without been logged as error.
19 | func NewRequeueNeeded(reason string) *RequeueNeeded {
20 | return &RequeueNeeded{
21 | reason: reason,
22 | }
23 | }
24 |
25 | // NewRequeueNeededAfter constructs new RequeueNeededAfter to
26 | // instruct controller-runtime to requeue the processing item after specified duration without been logged as error.
27 | func NewRequeueNeededAfter(reason string, duration time.Duration) *RequeueNeededAfter {
28 | return &RequeueNeededAfter{
29 | reason: reason,
30 | duration: duration,
31 | }
32 | }
33 |
34 | var _ error = &RequeueNeeded{}
35 |
36 | // An error to instruct controller-runtime to requeue the processing item without been logged as error.
37 | // This should be used when a "error condition" occurrence is sort of expected and can be resolved by retry.
38 | // e.g. a dependency haven't been fulfilled yet.
39 | type RequeueNeeded struct {
40 | reason string
41 | }
42 |
43 | func (e *RequeueNeeded) Reason() string {
44 | return e.reason
45 | }
46 |
47 | func (e *RequeueNeeded) Error() string {
48 | return fmt.Sprintf("requeue needed: %v", e.reason)
49 | }
50 |
51 | var _ error = &RequeueNeededAfter{}
52 |
53 | // An error to instruct controller-runtime to requeue the processing item after specified duration without been logged as error.
54 | // This should be used when a "error condition" occurrence is sort of expected and can be resolved by retry.
55 | // e.g. a dependency haven't been fulfilled yet, and expected it to be fulfilled after duration.
56 | // Note: use this with care,a simple wait might suits your use case better.
57 | type RequeueNeededAfter struct {
58 | reason string
59 | duration time.Duration
60 | }
61 |
62 | func (e *RequeueNeededAfter) Reason() string {
63 | return e.reason
64 | }
65 |
66 | func (e *RequeueNeededAfter) Duration() time.Duration {
67 | return e.duration
68 | }
69 |
70 | func (e *RequeueNeededAfter) Error() string {
71 | return fmt.Sprintf("requeue needed after %v: %v", e.duration, e.reason)
72 | }
73 |
--------------------------------------------------------------------------------
/pkg/runtime/reconcile.go:
--------------------------------------------------------------------------------
1 | package runtime
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "time"
7 |
8 | ctrl "sigs.k8s.io/controller-runtime"
9 | )
10 |
11 | // HandleReconcileError will handle errors from reconcile handlers, which respects runtime errors.
12 | func HandleReconcileError(err error) (ctrl.Result, error) {
13 | if err == nil {
14 | return ctrl.Result{}, nil
15 | }
16 |
17 | retryErr := NewRetryError()
18 | if errors.As(err, &retryErr) {
19 | return ctrl.Result{RequeueAfter: time.Second * 20}, nil
20 | }
21 |
22 | var requeueNeededAfter *RequeueNeededAfter
23 | if errors.As(err, &requeueNeededAfter) {
24 | return ctrl.Result{RequeueAfter: requeueNeededAfter.Duration()}, nil
25 | }
26 |
27 | var requeueNeeded *RequeueNeeded
28 | if errors.As(err, &requeueNeeded) {
29 | fmt.Print("requeue", "reason", requeueNeeded.Reason())
30 | return ctrl.Result{Requeue: true}, nil
31 | }
32 |
33 | return ctrl.Result{RequeueAfter: time.Minute * 10}, err
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/utils/common_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestChunks(t *testing.T) {
11 |
12 | type test struct {
13 | sliceLen int
14 | chunkSize int
15 | wantChunksLen int
16 | wantLastChunkLen int
17 | }
18 |
19 | tests := []test{
20 | {0, -1, 0, 0},
21 | {0, 0, 0, 0},
22 | {0, 1, 0, 0},
23 | {1, 1, 1, 1},
24 | {2, 1, 2, 1},
25 | {10, 2, 5, 2},
26 | {102, 10, 11, 2},
27 | }
28 |
29 | for _, tt := range tests {
30 | t.Run(fmt.Sprintf("sliceLen=%d, chunkSize=%d", tt.sliceLen, tt.chunkSize), func(t *testing.T) {
31 | slice := makeIntSlice(tt.sliceLen)
32 | chunks := Chunks(slice, tt.chunkSize)
33 | gotChunksLen := len(chunks)
34 | if gotChunksLen != tt.wantChunksLen {
35 | t.Errorf("number of chunks does not match, want=%d, got=%d", tt.wantChunksLen, gotChunksLen)
36 | }
37 | if gotChunksLen > 0 {
38 | lastChunk := chunks[gotChunksLen-1]
39 | if len(lastChunk) != tt.wantLastChunkLen {
40 | t.Errorf("last chunk size does not match, want=%d, got=%d", tt.wantLastChunkLen, len(lastChunk))
41 | }
42 | }
43 | })
44 | }
45 | }
46 |
47 | func makeIntSlice(s int) []int {
48 | out := make([]int, s)
49 | for i := 0; i < s; i++ {
50 | out[i] = i
51 | }
52 | return out
53 | }
54 |
55 | func TestSet(t *testing.T) {
56 |
57 | t.Run("empty set", func(t *testing.T) {
58 | s := Set[int]{}
59 | s.Put(1)
60 | assert.True(t, s.Contains(1))
61 | })
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/utils/condition.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 | )
6 |
7 | func GetNewConditions(conditions []v1.Condition, newCond v1.Condition) []v1.Condition {
8 | newConditions := make([]v1.Condition, 0)
9 |
10 | found := false
11 | for _, cond := range conditions {
12 | if cond.Type == newCond.Type {
13 | // Update existing condition. Time is kept only if status is unchanged.
14 | newCond.LastTransitionTime = cond.LastTransitionTime
15 | if cond.Status != newCond.Status {
16 | newCond.LastTransitionTime = v1.Now()
17 | }
18 | newConditions = append(newConditions, newCond)
19 | found = true
20 | } else {
21 | newConditions = append(newConditions, cond)
22 | }
23 | }
24 |
25 | if !found {
26 | // Add new condition instead.
27 | newCond.LastTransitionTime = v1.Now()
28 | newConditions = append(newConditions, newCond)
29 | }
30 |
31 | return newConditions
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/utils/gwlog/actions.go:
--------------------------------------------------------------------------------
1 | package gwlog
2 |
3 | const ReconcileStart = "reconcile_start"
4 | const ReconcileEnd = "reconcile_end"
5 |
--------------------------------------------------------------------------------
/pkg/utils/gwlog/metadata.go:
--------------------------------------------------------------------------------
1 | package gwlog
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/google/uuid"
7 | )
8 |
9 | type key string
10 |
11 | const metadataKey key = "metadata_key"
12 | const traceID string = "trace_id"
13 |
14 | type metadata struct {
15 | m map[string]string
16 | }
17 |
18 | func (mv *metadata) set(key, val string) {
19 | mv.m[key] = val
20 | }
21 |
22 | func newMetadata() *metadata {
23 | return &metadata{
24 | m: make(map[string]string),
25 | }
26 | }
27 |
28 | func NewTrace(ctx context.Context) context.Context {
29 | currID := uuid.New()
30 |
31 | newCtx := context.WithValue(ctx, metadataKey, newMetadata())
32 | AddMetadata(newCtx, traceID, currID.String())
33 |
34 | return newCtx
35 | }
36 |
37 | func AddMetadata(ctx context.Context, key, value string) {
38 | if ctx.Value(metadataKey) != nil {
39 | ctx.Value(metadataKey).(*metadata).set(key, value)
40 | }
41 | }
42 |
43 | func getMetadata(ctx context.Context) []interface{} {
44 | var fields []interface{}
45 |
46 | if ctx.Value(metadataKey) != nil {
47 | for k, v := range ctx.Value(metadataKey).(*metadata).m {
48 | if k == traceID {
49 | // skip since there's a separate method to grab the trace id
50 | continue
51 | }
52 | fields = append(fields, k)
53 | fields = append(fields, v)
54 | }
55 | }
56 | return fields
57 | }
58 |
59 | func GetTraceID(ctx context.Context) string {
60 | if ctx.Value(metadataKey) != nil {
61 | m := ctx.Value(metadataKey).(*metadata).m
62 | if m == nil {
63 | return ""
64 | }
65 | return ctx.Value(metadataKey).(*metadata).m[traceID]
66 | }
67 | return ""
68 | }
69 |
70 | func StartReconcileTrace(ctx context.Context, log Logger, k8sresourcetype, name, namespace string) context.Context {
71 | ctx = NewTrace(ctx)
72 | AddMetadata(ctx, "type", k8sresourcetype)
73 | AddMetadata(ctx, "name", name)
74 | AddMetadata(ctx, "namespace", namespace)
75 |
76 | log.Infow(ctx, ReconcileStart, getMetadata(ctx)...)
77 |
78 | return ctx
79 | }
80 |
81 | func EndReconcileTrace(ctx context.Context, log Logger) {
82 | log.Infow(ctx, ReconcileEnd, getMetadata(ctx)...)
83 | }
84 |
--------------------------------------------------------------------------------
/pkg/utils/gwlog/metadata_test.go:
--------------------------------------------------------------------------------
1 | package gwlog
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func TestGetTrace(t *testing.T) {
10 | if GetTraceID(context.TODO()) != "" {
11 | t.Errorf("expected context with no trace_id to return empty string")
12 | }
13 |
14 | if GetTraceID(NewTrace(context.TODO())) == "" {
15 | t.Errorf("expected context with trace_id to return non-empty string")
16 | }
17 | }
18 |
19 | func TestMetadata(t *testing.T) {
20 | ctx := NewTrace(context.TODO())
21 | AddMetadata(ctx, "foo", "bar")
22 |
23 | md := getMetadata(ctx)
24 | mdMap := map[string]bool{}
25 | for _, m := range md {
26 | mdMap[fmt.Sprint(m)] = true
27 | }
28 |
29 | if !mdMap["foo"] || !mdMap["bar"] {
30 | t.Errorf("expected context to have metadata with key foo and val bar, got %s", md)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/utils/pod_condition.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | corev1 "k8s.io/api/core/v1"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | "time"
7 | )
8 |
9 | func PodHasReadinessGate(pod *corev1.Pod, conditionType corev1.PodConditionType) bool {
10 | if pod == nil {
11 | return false
12 | }
13 | for _, gate := range pod.Spec.ReadinessGates {
14 | if gate.ConditionType == conditionType {
15 | return true
16 | }
17 | }
18 | return false
19 | }
20 |
21 | // Copied from: k8s.io/apimachinery/pkg/apis/meta
22 | func FindPodStatusCondition(conditions []corev1.PodCondition, conditionType corev1.PodConditionType) *corev1.PodCondition {
23 | for i := range conditions {
24 | if conditions[i].Type == conditionType {
25 | return &conditions[i]
26 | }
27 | }
28 | return nil
29 | }
30 |
31 | // Copied from: k8s.io/apimachinery/pkg/apis/meta
32 | func SetPodStatusCondition(conditions *[]corev1.PodCondition, newCondition corev1.PodCondition) {
33 | if conditions == nil {
34 | return
35 | }
36 | existingCondition := FindPodStatusCondition(*conditions, newCondition.Type)
37 | if existingCondition == nil {
38 | if newCondition.LastTransitionTime.IsZero() {
39 | newCondition.LastTransitionTime = metav1.NewTime(time.Now())
40 | }
41 | *conditions = append(*conditions, newCondition)
42 | return
43 | }
44 |
45 | if existingCondition.Status != newCondition.Status {
46 | existingCondition.Status = newCondition.Status
47 | if !newCondition.LastTransitionTime.IsZero() {
48 | existingCondition.LastTransitionTime = newCondition.LastTransitionTime
49 | } else {
50 | existingCondition.LastTransitionTime = metav1.NewTime(time.Now())
51 | }
52 | }
53 |
54 | existingCondition.Reason = newCondition.Reason
55 | existingCondition.Message = newCondition.Message
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/utils/priority_queue.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "fmt"
4 |
5 | // An Item is something we manage in a priority queue.
6 | type Item struct {
7 | Value any
8 | Priority int32 // The priority of the item in the queue.
9 | // The Index is needed by update and is maintained by the heap.Interface methods.
10 | Index int // The Index of the item in the heap.
11 | }
12 |
13 | // A PriorityQueue implements heap.Interface and holds Items.
14 | type PriorityQueue []*Item
15 |
16 | func (pq PriorityQueue) Len() int { return len(pq) }
17 |
18 | func (pq PriorityQueue) Less(i, j int) bool {
19 | // We want Pop to give us the highest, not lowest, priority so we use greater than here.
20 | return pq[i].Priority < pq[j].Priority
21 | }
22 |
23 | func (pq PriorityQueue) Swap(i, j int) {
24 | pq[i], pq[j] = pq[j], pq[i]
25 | pq[i].Index = i
26 | pq[j].Index = j
27 | }
28 |
29 | func (pq *PriorityQueue) Push(x any) {
30 | n := len(*pq)
31 | item := x.(*Item)
32 | item.Index = n
33 | *pq = append(*pq, item)
34 | }
35 |
36 | // Peek returns the highest priority item without removing it from the queue.
37 | // Returns nil and an error if the queue is empty.
38 | func (pq *PriorityQueue) Peek() (*Item, error) {
39 | if len(*pq) == 0 {
40 | return nil, fmt.Errorf("priority queue is empty")
41 | }
42 | return (*pq)[len(*pq)-1], nil
43 | }
44 |
45 | func (pq *PriorityQueue) Pop() any {
46 | old := *pq
47 | n := len(old)
48 | item := old[n-1]
49 | old[n-1] = nil // don't stop the GC from reclaiming the item eventually
50 | item.Index = -1 // for safety
51 | *pq = old[0 : n-1]
52 | return item
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/utils/retry/backoff.go:
--------------------------------------------------------------------------------
1 | package retry
2 |
3 | import (
4 | "math"
5 | "math/rand"
6 | "sync"
7 | "time"
8 | )
9 |
10 | // Backoff is the backoff interface
11 | type Backoff interface {
12 | Reset()
13 | Duration() time.Duration
14 | }
15 |
16 | // SimpleBackoff is the default simple backoff
17 | type SimpleBackoff struct {
18 | current time.Duration
19 | start time.Duration
20 | max time.Duration
21 | jitterMultiple float64
22 | multiple float64
23 | mu sync.Mutex
24 | }
25 |
26 | // NewSimpleBackoff creates a Backoff which ranges from min to max increasing by multiple each time.
27 | // It also adds (and yes, the jitter is always added, never subtracted) a random amount of jitter up to jitterMultiple
28 | // percent (that is, jitterMultiple = 0.0 is no jitter, 0.15 is 15% added jitter). The total time/ may exceed "max"
29 | // when accounting for jitter, such that the absolute max is max + max * jitterMultiple
30 | func NewSimpleBackoff(min, max time.Duration, jitterMultiple, multiple float64) *SimpleBackoff {
31 | return &SimpleBackoff{
32 | start: min,
33 | current: min,
34 | max: max,
35 | jitterMultiple: jitterMultiple,
36 | multiple: multiple,
37 | }
38 | }
39 |
40 | // Duration gets the current duration including jitter
41 | func (sb *SimpleBackoff) Duration() time.Duration {
42 | sb.mu.Lock()
43 | defer sb.mu.Unlock()
44 | ret := sb.current
45 | sb.current = time.Duration(math.Min(float64(sb.max.Nanoseconds()), float64(sb.current.Nanoseconds())*sb.multiple))
46 | return AddJitter(ret, time.Duration(int64(float64(ret)*sb.jitterMultiple)))
47 | }
48 |
49 | // Reset resets the backoff
50 | func (sb *SimpleBackoff) Reset() {
51 | sb.mu.Lock()
52 | defer sb.mu.Unlock()
53 | sb.current = sb.start
54 | }
55 |
56 | // AddJitter adds an amount of jitter between 0 and the given jitter to the given duration
57 | func AddJitter(duration time.Duration, jitter time.Duration) time.Duration {
58 | var randJitter int64
59 | if jitter.Nanoseconds() == 0 {
60 | randJitter = 0
61 | } else {
62 | randJitter = rand.Int63n(jitter.Nanoseconds())
63 | }
64 | return time.Duration(duration.Nanoseconds() + randJitter)
65 | }
66 |
--------------------------------------------------------------------------------
/pkg/utils/retry/errors.go:
--------------------------------------------------------------------------------
1 | package retry
2 |
3 | // Retriable is the retry interface
4 | type Retriable interface {
5 | Retry() bool
6 | }
7 |
8 | // DefaultRetriable is the default retryable
9 | type DefaultRetriable struct {
10 | retry bool
11 | }
12 |
13 | // Retry does the retry
14 | func (dr DefaultRetriable) Retry() bool {
15 | return dr.retry
16 | }
17 |
18 | // NewRetriable creates a new Retriable
19 | func NewRetriable(retry bool) Retriable {
20 | return DefaultRetriable{
21 | retry: retry,
22 | }
23 | }
24 |
25 | // RetriableError interface
26 | type RetriableError interface {
27 | Retriable
28 | error
29 | }
30 |
31 | // DefaultRetriableError is the default retriable error
32 | type DefaultRetriableError struct {
33 | Retriable
34 | error
35 | }
36 |
37 | // NewRetriableError returns a new retriable error
38 | func NewRetriableError(retriable Retriable, err error) RetriableError {
39 | return &DefaultRetriableError{
40 | retriable,
41 | err,
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/utils/retry/retry.go:
--------------------------------------------------------------------------------
1 | // Package retry is a retry with backoff implementation
2 | package retry
3 |
4 | import (
5 | "context"
6 |
7 | "github.com/aws/aws-application-networking-k8s/pkg/utils/ttime"
8 | )
9 |
10 | var _time ttime.Time = &ttime.DefaultTime{}
11 |
12 | // WithBackoff takes a Backoff and a function to call that returns an error
13 | // If the error is nil then the function will no longer be called
14 | // If the error is Retriable then that will be used to determine if it should be retried
15 | func WithBackoff(backoff Backoff, fn func() error) error {
16 | return WithBackoffCtx(context.Background(), backoff, fn)
17 | }
18 |
19 | // WithBackoffCtx takes a context, a Backoff, and a function to call that returns an error
20 | // If the context is done, nil will be returned
21 | // If the error is nil then the function will no longer be called
22 | // If the error is Retriable then that will be used to determine if it should be retried
23 | func WithBackoffCtx(ctx context.Context, backoff Backoff, fn func() error) error {
24 | var err error
25 | for {
26 | select {
27 | case <-ctx.Done():
28 | return nil
29 | default:
30 | }
31 | err = fn()
32 | retriableErr, isRetriableErr := err.(Retriable)
33 | if err == nil || (isRetriableErr && !retriableErr.Retry()) {
34 | return err
35 | }
36 | _time.Sleep(backoff.Duration())
37 | }
38 | }
39 |
40 | // NWithBackoff takes a Backoff, a maximum number of tries 'n', and a
41 | // function that returns an error. The function is called until either it does
42 | // not return an error or the maximum tries have been reached.
43 | // If the error returned is Retriable, the Retriability of it will be respected.
44 | // If the number of tries is exhausted, the last error will be returned.
45 | func NWithBackoff(backoff Backoff, n int, fn func() error) error {
46 | return NWithBackoffCtx(context.Background(), backoff, n, fn)
47 | }
48 |
49 | // NWithBackoffCtx takes a context, a Backoff, a maximum number of tries 'n', and a function that returns an error.
50 | // The function is called until it does not return an error, the context is done, or the maximum tries have been
51 | // reached.
52 | // If the error returned is Retriable, the Retriability of it will be respected.
53 | // If the number of tries is exhausted, the last error will be returned.
54 | func NWithBackoffCtx(ctx context.Context, backoff Backoff, n int, fn func() error) error {
55 | var err error
56 | _ = WithBackoffCtx(ctx, backoff, func() error {
57 | err = fn()
58 | n--
59 | if n == 0 {
60 | // Break out after n tries
61 | return nil
62 | }
63 | return err
64 | })
65 | return err
66 | }
67 |
--------------------------------------------------------------------------------
/pkg/utils/ttime/ttime.go:
--------------------------------------------------------------------------------
1 | package ttime
2 |
3 | import "time"
4 |
5 | // Time represents an implementation for this package's methods
6 | type Time interface {
7 | Now() time.Time
8 | Sleep(d time.Duration)
9 | After(d time.Duration) <-chan time.Time
10 | AfterFunc(d time.Duration, f func()) Timer
11 | }
12 |
13 | // Timer is the timer interface
14 | type Timer interface {
15 | Reset(d time.Duration) bool
16 | Stop() bool
17 | }
18 |
19 | // DefaultTime is a Time that behaves normally
20 | type DefaultTime struct{}
21 |
22 | // Now returns the current time
23 | func (*DefaultTime) Now() time.Time {
24 | return time.Now()
25 | }
26 |
27 | // Sleep sleeps for the given duration
28 | func (*DefaultTime) Sleep(d time.Duration) {
29 | time.Sleep(d)
30 | }
31 |
32 | // After sleeps for the given duration and then writes to to the returned channel
33 | func (*DefaultTime) After(d time.Duration) <-chan time.Time {
34 | return time.After(d)
35 | }
36 |
37 | // AfterFunc waits for the duration to elapse and then calls f in its own
38 | // goroutine. It returns a Timer that can be used to cancel the call using its
39 | // Stop method.
40 | func (*DefaultTime) AfterFunc(d time.Duration, f func()) Timer {
41 | return time.AfterFunc(d, f)
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/webhook/core/context.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
6 | )
7 |
8 | type contextKey string
9 |
10 | const (
11 | contextKeyAdmissionRequest contextKey = "admissionRequest"
12 | )
13 |
14 | func ContextGetAdmissionRequest(ctx context.Context) *admission.Request {
15 | if v := ctx.Value(contextKeyAdmissionRequest); v != nil {
16 | return v.(*admission.Request)
17 | }
18 | return nil
19 | }
20 |
21 | func ContextWithAdmissionRequest(ctx context.Context, req admission.Request) context.Context {
22 | return context.WithValue(ctx, contextKeyAdmissionRequest, &req)
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/webhook/core/context_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "github.com/stretchr/testify/assert"
6 | admissionv1 "k8s.io/api/admission/v1"
7 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
8 | "testing"
9 | )
10 |
11 | func TestContextGetAdmissionRequestAndContextWithAdmissionRequest(t *testing.T) {
12 | type args struct {
13 | req *admission.Request
14 | }
15 | tests := []struct {
16 | name string
17 | args args
18 | want *admission.Request
19 | }{
20 | {
21 | name: "with request",
22 | args: args{
23 | req: &admission.Request{
24 | AdmissionRequest: admissionv1.AdmissionRequest{
25 | UID: "1",
26 | },
27 | },
28 | },
29 | want: &admission.Request{
30 | AdmissionRequest: admissionv1.AdmissionRequest{
31 | UID: "1",
32 | },
33 | },
34 | },
35 | {
36 | name: "without request",
37 | args: args{
38 | req: nil,
39 | },
40 | want: nil,
41 | },
42 | }
43 | for _, tt := range tests {
44 | t.Run(tt.name, func(t *testing.T) {
45 | ctx := context.Background()
46 | if tt.args.req != nil {
47 | ctx = ContextWithAdmissionRequest(ctx, *tt.args.req)
48 | }
49 | got := ContextGetAdmissionRequest(ctx)
50 | assert.Equal(t, tt.want, got)
51 | })
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/webhook/core/mutator.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
6 | "k8s.io/apimachinery/pkg/runtime"
7 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
8 | )
9 |
10 | //go:generate mockgen -destination mutator_mocks.go -package core github.com/aws/aws-application-networking-k8s/pkg/webhook/core Mutator
11 | type Mutator interface {
12 | // Prototype returns a prototype of Object for this admission request.
13 | Prototype(req admission.Request) (runtime.Object, error)
14 |
15 | // MutateCreate handles Object creation and returns the object after mutation and error if any.
16 | MutateCreate(ctx context.Context, obj runtime.Object) (runtime.Object, error)
17 | // MutateUpdate handles Object update and returns the object after mutation and error if any.
18 | MutateUpdate(ctx context.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error)
19 | }
20 |
21 | // MutatingWebhookForMutator creates a new mutating Webhook.
22 | func MutatingWebhookForMutator(log gwlog.Logger, scheme *runtime.Scheme, mutator Mutator) *admission.Webhook {
23 | return &admission.Webhook{
24 | Handler: &mutatingHandler{
25 | log: log,
26 | mutator: mutator,
27 | decoder: admission.NewDecoder(scheme),
28 | },
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/webhook/pod_mutator.go:
--------------------------------------------------------------------------------
1 | package webhook
2 |
3 | import (
4 | "context"
5 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
6 | "github.com/aws/aws-application-networking-k8s/pkg/webhook/core"
7 | corev1 "k8s.io/api/core/v1"
8 | "k8s.io/apimachinery/pkg/runtime"
9 | ctrl "sigs.k8s.io/controller-runtime"
10 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
11 | )
12 |
13 | const (
14 | apiPathMutatePod = "/mutate-pod"
15 | )
16 |
17 | func NewPodMutator(log gwlog.Logger, scheme *runtime.Scheme, podReadinessGateInjector *PodReadinessGateInjector) *podMutator {
18 | return &podMutator{
19 | log: log,
20 | podReadinessGateInjector: podReadinessGateInjector,
21 | scheme: scheme,
22 | }
23 | }
24 |
25 | var _ core.Mutator = &podMutator{}
26 |
27 | type podMutator struct {
28 | log gwlog.Logger
29 | podReadinessGateInjector *PodReadinessGateInjector
30 | scheme *runtime.Scheme
31 | }
32 |
33 | func (m *podMutator) Prototype(_ admission.Request) (runtime.Object, error) {
34 | return &corev1.Pod{}, nil
35 | }
36 |
37 | func (m *podMutator) MutateCreate(ctx context.Context, obj runtime.Object) (runtime.Object, error) {
38 | pod := obj.(*corev1.Pod)
39 | if err := m.podReadinessGateInjector.MutateCreate(ctx, pod); err != nil {
40 | return pod, err
41 | }
42 | return pod, nil
43 | }
44 |
45 | func (m *podMutator) MutateUpdate(ctx context.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
46 | return obj, nil
47 | }
48 |
49 | func (m *podMutator) SetupWithManager(log gwlog.Logger, mgr ctrl.Manager) {
50 | mgr.GetWebhookServer().Register(apiPathMutatePod, core.MutatingWebhookForMutator(log, m.scheme, m))
51 | }
52 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Babel==2.13.1
2 | certifi==2024.7.4
3 | charset-normalizer==3.3.2
4 | click==8.1.7
5 | colorama==0.4.6
6 | ghp-import==2.1.0
7 | idna==3.7
8 | Jinja2==3.1.6
9 | Markdown==3.5.1
10 | MarkupSafe==2.1.3
11 | mergedeep==1.3.4
12 | mkdocs==1.5.3
13 | mkdocs-material==9.4.12
14 | mkdocs-material-extensions==1.3.1
15 | mike==2.1.1
16 | packaging==23.2
17 | paginate==0.5.6
18 | pathspec==0.11.2
19 | platformdirs==4.0.0
20 | Pygments==2.17.2
21 | pymdown-extensions==10.4
22 | python-dateutil==2.8.2
23 | PyYAML==6.0.1
24 | pyyaml_env_tag==0.1
25 | regex==2023.10.3
26 | requests==2.32.0
27 | six==1.16.0
28 | urllib3==2.2.2
29 | watchdog==3.0.0
30 |
--------------------------------------------------------------------------------
/scripts/gen-webhook-secret.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Use this script to update the webhook secret post-deployment. Alternatively,
4 | # you can use patch-deploy-yaml.sh prior to deployment.
5 | #
6 | # Generates a certificate for use by the controller webhook
7 | # You can also manually re-create the webhook secret using your own PKI
8 |
9 | TEMP_KEY=`mktemp`
10 | TEMP_CERT=`mktemp`
11 |
12 | WEBHOOK_SVC_NAME=webhook-service
13 | WEBHOOK_NAME=aws-appnet-gwc-mutating-webhook
14 | WEBHOOK_NAMESPACE=aws-application-networking-system
15 | WEBHOOK_SECRET_NAME=webhook-cert
16 |
17 | echo "Generating certificate for webhook"
18 | HOST=${WEBHOOK_SVC_NAME}.${WEBHOOK_NAMESPACE}.svc
19 | openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout ${TEMP_KEY} -out ${TEMP_CERT} -subj "/CN=${HOST}/O=${HOST}" \
20 | -addext "subjectAltName = DNS:${HOST}, DNS:${HOST}.cluster.local"
21 |
22 | CERT_B64=`cat $TEMP_CERT | base64`
23 |
24 | echo "Recreating webhook secret"
25 | kubectl delete secret $WEBHOOK_SECRET_NAME --namespace $WEBHOOK_NAMESPACE
26 | kubectl create secret tls $WEBHOOK_SECRET_NAME --namespace $WEBHOOK_NAMESPACE --cert=${TEMP_CERT} --key=${TEMP_KEY}
27 |
28 | echo "Patching webhook with new cert"
29 | kubectl patch mutatingwebhookconfigurations.admissionregistration.k8s.io $WEBHOOK_NAME \
30 | --namespace $WEBHOOK_NAMESPACE --type='json' \
31 | -p="[{'op': 'replace', 'path': '/webhooks/0/clientConfig/caBundle', 'value': '${CERT_B64}'}]"
32 |
33 | rm $TEMP_KEY $TEMP_CERT
34 | echo "Done"
--------------------------------------------------------------------------------
/scripts/lib/common.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # common.sh contains commonly used functions, meant to be imported by other
4 | # bash scripts.
5 |
6 | LIB_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
7 |
8 | source "$LIB_DIR/logging.sh"
9 |
10 | # check_is_installed checks to see if the supplied executable is installed and
11 | # exits if not. An optional second argument is an extra message to display when
12 | # the supplied executable is not installed.
13 | #
14 | # Usage:
15 | #
16 | # check_is_installed PROGRAM [ MSG ]
17 | #
18 | # Example:
19 | #
20 | # check_is_installed kind "You can install kind with the helper scripts/install-kind.sh"
21 | check_is_installed() {
22 | local __name="$1"
23 | local __extra_msg="$2"
24 | if ! is_installed "$__name"; then
25 | error_msg "Missing required binary in PATH: '$__name'"
26 | error_msg "Please install $__name before running this script."
27 | if [[ -n $__extra_msg ]]; then
28 | error_msg ""
29 | error_msg "$__extra_msg"
30 | error_msg ""
31 | fi
32 | exit 1
33 | fi
34 | }
35 |
36 | is_installed() {
37 | local __name="$1"
38 | if $(which $__name >/dev/null 2>&1); then
39 | return 0
40 | else
41 | return 1
42 | fi
43 | }
44 |
45 | function sed_inplace() {
46 | local pattern=$1
47 | local replacement=$2
48 | local file=$3
49 |
50 | if [[ "$OSTYPE" == "darwin"* ]]; then
51 | # macOS uses BSD sed
52 | sed -i '' "s|$pattern|$replacement|g" "$file"
53 | else
54 | # Assuming Linux uses GNU sed
55 | sed -i "s|$pattern|$replacement|g" "$file"
56 | fi
57 | }
--------------------------------------------------------------------------------
/scripts/lib/logging.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # logging.sh contains functions for writing log messages to the console for
4 | # three different severities: debug, info and error.
5 |
6 | # Prints out a message with an optional second argument indicating the
7 | # "indentation level" for the message. If the indentation level argument is
8 | # missing, we look for the existence of an environs variable called
9 | # "indent_level" and use that.
10 | _indented_msg() {
11 | local __msg=${1:-}
12 | local __indent_level=${2:-}
13 | local indent=""
14 | if [ -n "$__indent_level" ]; then
15 | indent="$( for each in $( seq 0 $__indent_level ); do printf " "; done )"
16 | fi
17 |
18 | local timestamp=$(date -Is)
19 |
20 | echo "$timestamp $__indent$__msg"
21 | }
22 |
23 | # debug_msg prints out a supplied message if the ACK_TEST_DEBUGGING_MODE environ
24 | # variable is set.
25 | debug_msg() {
26 | local __debug="${ACK_TEST_DEBUGGING_MODE:-""}"
27 | if [ ! -n "$__debug" ]; then
28 | return 0
29 | fi
30 |
31 | local __msg=${1:-}
32 | local __indent=${2:-}
33 | local __debug_prefix="${DEBUG_PREFIX:-"[DEBUG] "}"
34 | _indented_msg "$__debug_prefix$__msg" $__indent
35 | }
36 |
37 | # info_msg prints out a supplied message if the DEBUG environs variable is
38 | # set.
39 | info_msg() {
40 | local __msg=${1:-}
41 | local __indent=${2:-}
42 | local __info_prefix="${INFO_PREFIX:-"[INFO] "}"
43 | _indented_msg "$__info_prefix$__msg" $__indent
44 | }
45 |
46 | # debug_msg prints out a supplied message if the DEBUG environs variable is
47 | # set.
48 | error_msg() {
49 | local __msg=${1:-}
50 | local __indent=${2:-}
51 | local __error_prefix="${ERROR_PREFIX:-"[ERROR] "}"
52 | >&2 _indented_msg "$__error_prefix$__msg" $__indent
53 | }
--------------------------------------------------------------------------------
/scripts/lib/login.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # login.sh contains functions for logging into container repositories.
4 | # Note: These functions are not placed inside tools specific file like
5 | # helm.sh, because those files ensure binaries(ex: kind) that are not
6 | # really needed for simple actions like repository login.
7 | # A future refactor can make those files more modular and then login
8 | # functions can be refactored in tool specific file like docker.sh
9 | # and helm.sh
10 |
11 | perform_docker_and_helm_login() {
12 | local full_url="$1"
13 | local registry_url=$(echo "$full_url" | cut -d'/' -f1)
14 |
15 | # Check if the registry URL is for the public ECR
16 | if [ "$registry_url" = "public.ecr.aws" ]; then
17 | local __pw=$(aws ecr-public get-login-password --region us-east-1)
18 | else
19 | local __pw=$(aws ecr get-login-password)
20 | fi
21 | echo "$__pw" | docker login --username AWS --password-stdin $registry_url
22 | export HELM_EXPERIMENTAL_OCI=1
23 | echo "$__pw" | helm registry login -u AWS --password-stdin $registry_url
24 | }
25 |
26 | ensure_binaries() {
27 | check_is_installed "aws"
28 | check_is_installed "docker"
29 | check_is_installed "helm"
30 | }
31 |
32 | ensure_binaries
33 |
--------------------------------------------------------------------------------
/scripts/load_env_variables.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # When Running the k8s Controller by GoLand IDE locally, it is required to set the environment variables, this script will generate a file called `envFile`
4 | # that contains all needed environment variables, this `envFile` file can be use by GoLand "EnvFile" plugin
5 | # When config the "green arrow"(how we `run` or `debug` this project) in GoLand, we could set a "before launch" task to run this script `load_env_variables.sh`, and set the "EnvFile" plugin to load the `envFile` file
6 | # "EnvFile" is a plugin, you can install it from GoLand plugin marketplace
7 |
8 | echo "Setting environment variables"
9 |
10 | > envFile
11 |
12 | # Set KUBEBUILDER_ASSETS if not set
13 | if [ -z "$KUBEBUILDER_ASSETS" ]; then
14 | KUBEBUILDER_ASSETS=${HOME}/.kubebuilder/bin
15 | fi
16 | echo "KUBEBUILDER_ASSETS=$KUBEBUILDER_ASSETS" >> envFile
17 |
18 | # Set CLUSTER_NAME if not set
19 | if [ -z "$CLUSTER_NAME" ]; then
20 | CLUSTER_NAME=$(kubectl config view --minify -o jsonpath='{.clusters[].name}' | rev | cut -d"/" -f1 | rev | cut -d"." -f1)
21 | fi
22 | echo "CLUSTER_NAME=$CLUSTER_NAME" >> envFile
23 |
24 | # Set CLUSTER_VPC_ID if not set
25 | if [ -z "$CLUSTER_VPC_ID" ]; then
26 | CLUSTER_VPC_ID=$(aws eks describe-cluster --name ${CLUSTER_NAME} | jq -r ".cluster.resourcesVpcConfig.vpcId")
27 | fi
28 | echo "CLUSTER_VPC_ID=$CLUSTER_VPC_ID" >> envFile
29 |
30 | # Set AWS_ACCOUNT_ID if not set
31 | if [ -z "$AWS_ACCOUNT_ID" ]; then
32 | AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
33 | fi
34 | echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" >> envFile
35 |
36 | if [ -z "$REGION" ]; then
37 | REGION=us-west-2
38 | fi
39 | echo "REGION=$REGION" >> envFile
40 |
41 | echo "LOG_LEVEL=debug" >> envFile
42 |
--------------------------------------------------------------------------------
/test/pkg/test/context.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "go.uber.org/zap"
8 | "go.uber.org/zap/zaptest"
9 | )
10 |
11 | type loggerKey struct{}
12 |
13 | func NewContext(t *testing.T) context.Context {
14 | ctx := context.Background()
15 | ctx = context.WithValue(ctx, loggerKey{}, zaptest.NewLogger(t, zaptest.WrapOptions(
16 | zap.AddCaller(),
17 | zap.Development(),
18 | )).Sugar())
19 | return ctx
20 | }
21 |
22 | func Logger(ctx context.Context) *zap.SugaredLogger {
23 | return ctx.Value(loggerKey{}).(*zap.SugaredLogger)
24 | }
25 |
--------------------------------------------------------------------------------
/test/pkg/test/gateway.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
7 | )
8 |
9 | func (env *Framework) NewGateway(name string, namespace string) *gwv1.Gateway {
10 | gateway := New(
11 | &gwv1.Gateway{
12 | ObjectMeta: metav1.ObjectMeta{
13 | Name: name,
14 | Namespace: namespace,
15 | Annotations: map[string]string{
16 | "application-networking.k8s.aws/lattice-vpc-association": "true",
17 | },
18 | },
19 | Spec: gwv1.GatewaySpec{
20 | GatewayClassName: "amazon-vpc-lattice",
21 | Listeners: []gwv1.Listener{
22 | {
23 | Name: "http",
24 | Protocol: gwv1.HTTPProtocolType,
25 | Port: 80,
26 | },
27 | {
28 | Name: "https",
29 | Protocol: gwv1.HTTPSProtocolType,
30 | Port: 443,
31 | TLS: &gwv1.GatewayTLSConfig{
32 | Mode: lo.ToPtr(gwv1.TLSModeTerminate),
33 | CertificateRefs: []gwv1.SecretObjectReference{
34 | {
35 | Name: "dummy",
36 | },
37 | },
38 | },
39 | },
40 | {
41 | Name: "tls",
42 | Protocol: gwv1.TLSProtocolType,
43 | Port: 444,
44 | TLS: &gwv1.GatewayTLSConfig{
45 | Mode: lo.ToPtr(gwv1.TLSModePassthrough),
46 | },
47 | },
48 | },
49 | },
50 | Status: gwv1.GatewayStatus{},
51 | },
52 | )
53 | return gateway
54 | }
55 |
--------------------------------------------------------------------------------
/test/pkg/test/grpc_helloworld.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | appsv1 "k8s.io/api/apps/v1"
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | // https://github.com/grpc/grpc-go/tree/master/examples/helloworld
12 | func (env *Framework) NewGrpcHelloWorld(options GrpcAppOptions) (*appsv1.Deployment, *v1.Service) {
13 |
14 | deployment := New(&appsv1.Deployment{
15 | ObjectMeta: metav1.ObjectMeta{
16 | Namespace: options.Namespace,
17 | },
18 | Spec: appsv1.DeploymentSpec{
19 | Replicas: lo.ToPtr(int32(1)),
20 | Selector: &metav1.LabelSelector{
21 | MatchLabels: map[string]string{
22 | "app": options.AppName,
23 | },
24 | },
25 | Template: v1.PodTemplateSpec{
26 | ObjectMeta: metav1.ObjectMeta{
27 | Namespace: options.Namespace,
28 | Labels: map[string]string{
29 | "app": options.AppName,
30 | DiscoveryLabel: "true",
31 | },
32 | },
33 | Spec: v1.PodSpec{
34 | Containers: []v1.Container{{
35 | Name: options.AppName,
36 | Image: "aguilbau/hello-world-grpc:latest",
37 | }},
38 | },
39 | },
40 | },
41 | })
42 |
43 | service := New(&v1.Service{
44 | TypeMeta: metav1.TypeMeta{
45 | Kind: "Service",
46 | },
47 | ObjectMeta: metav1.ObjectMeta{
48 | Namespace: options.Namespace,
49 | },
50 | Spec: v1.ServiceSpec{
51 | Selector: map[string]string{
52 | "app": options.AppName,
53 | },
54 | Ports: []v1.ServicePort{
55 | {
56 | Name: "hello-world-grpc",
57 | Protocol: v1.ProtocolTCP,
58 | Port: int32(10051),
59 | TargetPort: intstr.FromInt(50051),
60 | },
61 | },
62 | },
63 | })
64 | return deployment, service
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/test/pkg/test/grpcbin.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | appsv1 "k8s.io/api/apps/v1"
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | type GrpcAppOptions struct {
12 | AppName string
13 | Namespace string
14 | }
15 |
16 | // https://github.com/moul/grpcbin
17 | func (env *Framework) NewGrpcBin(options GrpcAppOptions) (*appsv1.Deployment, *v1.Service) {
18 |
19 | deployment := New(&appsv1.Deployment{
20 | ObjectMeta: metav1.ObjectMeta{
21 | Namespace: options.Namespace,
22 | },
23 | Spec: appsv1.DeploymentSpec{
24 | Replicas: lo.ToPtr(int32(1)),
25 | Selector: &metav1.LabelSelector{
26 | MatchLabels: map[string]string{
27 | "app": options.AppName,
28 | },
29 | },
30 | Template: v1.PodTemplateSpec{
31 | ObjectMeta: metav1.ObjectMeta{
32 | Namespace: options.Namespace,
33 | Labels: map[string]string{
34 | "app": options.AppName,
35 | DiscoveryLabel: "true",
36 | },
37 | },
38 | Spec: v1.PodSpec{
39 | Containers: []v1.Container{{
40 | Name: options.AppName,
41 | Image: "moul/grpcbin:latest",
42 | }},
43 | },
44 | },
45 | },
46 | })
47 |
48 | service := New(&v1.Service{
49 | TypeMeta: metav1.TypeMeta{
50 | Kind: "Service",
51 | },
52 | ObjectMeta: metav1.ObjectMeta{
53 | Namespace: options.Namespace,
54 | },
55 | Spec: v1.ServiceSpec{
56 | Selector: map[string]string{
57 | "app": options.AppName,
58 | },
59 | Ports: []v1.ServicePort{
60 | {
61 | Name: "grpcbin-over-http",
62 | Protocol: v1.ProtocolTCP,
63 | Port: int32(19000),
64 | TargetPort: intstr.FromInt(9000),
65 | },
66 | {
67 | Name: "grpcbin-over-https",
68 | Protocol: v1.ProtocolTCP,
69 | Port: int32(19001),
70 | TargetPort: intstr.FromInt(9001),
71 | },
72 | },
73 | },
74 | })
75 | return deployment, service
76 | }
77 |
--------------------------------------------------------------------------------
/test/pkg/test/grpcroute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
7 | )
8 |
9 | func (env *Framework) NewGRPCRoute(namespace string, parentRefsGateway *gwv1.Gateway, rules []gwv1.GRPCRouteRule) *gwv1.GRPCRoute {
10 | grpcRoute := New(&gwv1.GRPCRoute{
11 | TypeMeta: metav1.TypeMeta{},
12 | ObjectMeta: metav1.ObjectMeta{
13 | Namespace: namespace,
14 | },
15 | Spec: gwv1.GRPCRouteSpec{
16 | CommonRouteSpec: gwv1.CommonRouteSpec{
17 | ParentRefs: []gwv1.ParentReference{{
18 | Name: gwv1.ObjectName(parentRefsGateway.Name),
19 | Namespace: (*gwv1.Namespace)(&parentRefsGateway.Namespace),
20 | SectionName: lo.ToPtr(gwv1.SectionName("https")),
21 | }},
22 | },
23 | Rules: rules,
24 | },
25 | })
26 |
27 | return grpcRoute
28 | }
29 |
--------------------------------------------------------------------------------
/test/pkg/test/grpcurl_runner.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | v1 "k8s.io/api/core/v1"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | )
7 |
8 | // https://github.com/fullstorydev/grpcurl
9 | func NewGrpcurlRunnerPod(name, namespace string) *v1.Pod {
10 | grpcurlPod := &v1.Pod{
11 | ObjectMeta: metav1.ObjectMeta{
12 | Namespace: namespace,
13 | Name: name,
14 | Labels: map[string]string{
15 | "app": "grpcurl-runner",
16 | },
17 | },
18 | Spec: v1.PodSpec{
19 | Containers: []v1.Container{
20 | {
21 | Name: "grpcurl-runner-container",
22 | // https://gallery.ecr.aws/a0j4q9e4/grpcurl-runner
23 | Image: "public.ecr.aws/a0j4q9e4/grpcurl-runner:latest",
24 | Command: []string{
25 | "/bin/sh",
26 | "-c",
27 | "while true; do sleep 5; done;",
28 | },
29 | },
30 | },
31 | },
32 | }
33 | return grpcurlPod
34 | }
35 |
--------------------------------------------------------------------------------
/test/pkg/test/header_match_httproute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | v1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
8 | )
9 |
10 | func (env *Framework) NewHeaderMatchHttpRoute(parentRefsGateway *gwv1.Gateway, services []*v1.Service) *gwv1.HTTPRoute {
11 | var rules []gwv1.HTTPRouteRule
12 | for _, service := range services {
13 | rule := gwv1.HTTPRouteRule{
14 | BackendRefs: []gwv1.HTTPBackendRef{{
15 | BackendRef: gwv1.BackendRef{
16 | BackendObjectReference: gwv1.BackendObjectReference{
17 | Name: gwv1.ObjectName(service.Name),
18 | Kind: lo.ToPtr(gwv1.Kind("Service")),
19 | Port: (*gwv1.PortNumber)(&service.Spec.Ports[0].Port),
20 | },
21 | },
22 | }},
23 | Matches: []gwv1.HTTPRouteMatch{
24 | {
25 | Headers: []gwv1.HTTPHeaderMatch{
26 | {
27 | Type: lo.ToPtr(gwv1.HeaderMatchExact),
28 | Name: "my-header-name1",
29 | Value: "my-header-value1",
30 | },
31 | {
32 | Type: lo.ToPtr(gwv1.HeaderMatchExact),
33 | Name: "my-header-name2",
34 | Value: "my-header-value2",
35 | },
36 | },
37 | },
38 | },
39 | }
40 | rules = append(rules, rule)
41 | }
42 | httpRoute := New(&gwv1.HTTPRoute{
43 | ObjectMeta: metav1.ObjectMeta{
44 | Namespace: env.namespace,
45 | },
46 | Spec: gwv1.HTTPRouteSpec{
47 | CommonRouteSpec: gwv1.CommonRouteSpec{
48 | ParentRefs: []gwv1.ParentReference{{
49 | Name: gwv1.ObjectName(parentRefsGateway.Name),
50 | SectionName: lo.ToPtr(gwv1.SectionName("http")),
51 | }},
52 | },
53 | Rules: rules,
54 | },
55 | })
56 |
57 | return httpRoute
58 | }
59 |
--------------------------------------------------------------------------------
/test/pkg/test/httpapp.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | appsv1 "k8s.io/api/apps/v1"
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | type HTTPAppOptions struct {
12 | Name string
13 | Namespace string // the object will be created in this namespace
14 | Port int
15 | TargetPort int
16 | MergeFromDeployment []*appsv1.Deployment
17 | MergeFromService []*v1.Service
18 | }
19 |
20 | func (env *Framework) NewHttpApp(options HTTPAppOptions) (*appsv1.Deployment, *v1.Service) {
21 | if options.Port == 0 {
22 | options.Port = 80
23 | }
24 | if options.TargetPort == 0 {
25 | options.TargetPort = 8090
26 | }
27 | deployment := New(&appsv1.Deployment{
28 | ObjectMeta: metav1.ObjectMeta{
29 | Namespace: options.Namespace,
30 | },
31 | Spec: appsv1.DeploymentSpec{
32 | Replicas: lo.ToPtr(int32(1)),
33 | Selector: &metav1.LabelSelector{
34 | MatchLabels: map[string]string{
35 | "app": options.Name,
36 | },
37 | },
38 | Template: v1.PodTemplateSpec{
39 | ObjectMeta: metav1.ObjectMeta{
40 | Namespace: options.Namespace,
41 | Labels: map[string]string{
42 | "app": options.Name,
43 | DiscoveryLabel: "true",
44 | },
45 | },
46 | Spec: v1.PodSpec{
47 | Containers: []v1.Container{{
48 | Name: options.Name,
49 | Image: "public.ecr.aws/x2j8p8w7/http-server:latest",
50 | Env: []v1.EnvVar{{
51 | Name: "PodName",
52 | Value: options.Name + " handler pod",
53 | }},
54 | }},
55 | },
56 | },
57 | },
58 | }, options.MergeFromDeployment...)
59 |
60 | service := New(&v1.Service{
61 | TypeMeta: metav1.TypeMeta{
62 | Kind: "Service",
63 | },
64 | ObjectMeta: metav1.ObjectMeta{
65 | Namespace: options.Namespace,
66 | Name: options.Name,
67 | },
68 | Spec: v1.ServiceSpec{
69 | Selector: map[string]string{
70 | "app": options.Name,
71 | },
72 | Ports: []v1.ServicePort{{
73 | Protocol: v1.ProtocolTCP,
74 | Port: int32(options.Port),
75 | TargetPort: intstr.FromInt(options.TargetPort),
76 | }},
77 | },
78 | }, options.MergeFromService...)
79 | return deployment, service
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/test/pkg/test/httproute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | corev1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
8 | )
9 |
10 | func (env *Framework) NewHttpRoute(parentRefsGateway *gwv1.Gateway, service *corev1.Service, kind string) *gwv1.HTTPRoute {
11 | var rules []gwv1.HTTPRouteRule
12 | rule := gwv1.HTTPRouteRule{
13 | BackendRefs: []gwv1.HTTPBackendRef{{
14 | BackendRef: gwv1.BackendRef{
15 | BackendObjectReference: gwv1.BackendObjectReference{
16 | Name: gwv1.ObjectName(service.Name),
17 | Namespace: (*gwv1.Namespace)(&service.Namespace),
18 | Kind: lo.ToPtr(gwv1.Kind(kind)),
19 | Port: (*gwv1.PortNumber)(&service.Spec.Ports[0].Port),
20 | },
21 | },
22 | }},
23 | }
24 | rules = append(rules, rule)
25 | parentNS := gwv1.Namespace(parentRefsGateway.Namespace)
26 | httpRoute := New(&gwv1.HTTPRoute{
27 | ObjectMeta: metav1.ObjectMeta{
28 | Namespace: service.Namespace,
29 | Name: service.Name,
30 | },
31 | Spec: gwv1.HTTPRouteSpec{
32 | CommonRouteSpec: gwv1.CommonRouteSpec{
33 | ParentRefs: []gwv1.ParentReference{{
34 | Name: gwv1.ObjectName(parentRefsGateway.Name),
35 | Namespace: &parentNS,
36 | }},
37 | },
38 | Rules: rules,
39 | },
40 | })
41 | return httpRoute
42 | }
43 |
--------------------------------------------------------------------------------
/test/pkg/test/httpsapp.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | appsv1 "k8s.io/api/apps/v1"
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | "k8s.io/apimachinery/pkg/util/intstr"
9 | )
10 |
11 | type HTTPsAppOptions struct {
12 | Name string
13 | Namespace string // the object will be created in this namespace
14 | Port int
15 | TargetPort int
16 | MergeFromDeployment []*appsv1.Deployment
17 | MergeFromService []*v1.Service
18 | }
19 |
20 | func (env *Framework) NewHttpsApp(options HTTPsAppOptions) (*appsv1.Deployment, *v1.Service) {
21 | if options.Port == 0 {
22 | options.Port = 443
23 | }
24 | if options.TargetPort == 0 {
25 | options.TargetPort = 443
26 | }
27 | deployment := New(&appsv1.Deployment{
28 | ObjectMeta: metav1.ObjectMeta{
29 | Namespace: options.Namespace,
30 | },
31 | Spec: appsv1.DeploymentSpec{
32 | Replicas: lo.ToPtr(int32(1)),
33 | Selector: &metav1.LabelSelector{
34 | MatchLabels: map[string]string{
35 | "app": options.Name,
36 | },
37 | },
38 | Template: v1.PodTemplateSpec{
39 | ObjectMeta: metav1.ObjectMeta{
40 | Namespace: options.Namespace,
41 | Labels: map[string]string{
42 | "app": options.Name,
43 | DiscoveryLabel: "true",
44 | },
45 | },
46 | Spec: v1.PodSpec{
47 | Containers: []v1.Container{{
48 | Name: options.Name,
49 | Image: "public.ecr.aws/x2j8p8w7/https-server:latest",
50 | Env: []v1.EnvVar{{
51 | Name: "PodName",
52 | Value: options.Name + " handler pod",
53 | }},
54 | }},
55 | },
56 | },
57 | },
58 | }, options.MergeFromDeployment...)
59 |
60 | service := New(&v1.Service{
61 | TypeMeta: metav1.TypeMeta{
62 | Kind: "Service",
63 | },
64 | ObjectMeta: metav1.ObjectMeta{
65 | Namespace: options.Namespace,
66 | Name: options.Name,
67 | },
68 | Spec: v1.ServiceSpec{
69 | Selector: map[string]string{
70 | "app": options.Name,
71 | },
72 | Ports: []v1.ServicePort{{
73 | Protocol: v1.ProtocolTCP,
74 | Port: int32(options.Port),
75 | TargetPort: intstr.FromInt(options.TargetPort),
76 | }},
77 | },
78 | }, options.MergeFromService...)
79 | return deployment, service
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/test/pkg/test/metadata.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "strings"
7 | "sync"
8 | "time"
9 |
10 | randomdata "github.com/Pallinder/go-randomdata"
11 | "github.com/imdario/mergo"
12 | "sigs.k8s.io/controller-runtime/pkg/client"
13 | )
14 |
15 | var (
16 | sequentialNumber = 0
17 | randomizer = rand.New(rand.NewSource(time.Now().UnixNano())) //nolint
18 | sequentialNumberLock = new(sync.Mutex)
19 | DiscoveryLabel = "testing.kubernetes.io"
20 | )
21 |
22 | func New[T client.Object](t T, mergeFrom ...T) T {
23 | if t.GetName() == "" {
24 | t.SetName(RandomName())
25 | }
26 | if t.GetNamespace() == "" {
27 | t.SetNamespace("e2e-test")
28 | }
29 | t.SetLabels(map[string]string{DiscoveryLabel: "true"})
30 | return MustMerge(t, mergeFrom...)
31 | }
32 |
33 | func MustMerge[T interface{}](dest T, srcs ...T) T {
34 | for _, src := range srcs {
35 | if err := mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithAppendSlice); err != nil {
36 | panic(fmt.Sprintf("Failed to merge object: %s", err))
37 | }
38 | }
39 | return dest
40 | }
41 |
42 | func RandomName() string {
43 | sequentialNumberLock.Lock()
44 | defer sequentialNumberLock.Unlock()
45 | sequentialNumber++
46 | return strings.ToLower(fmt.Sprintf("%s-%d-%s", randomdata.SillyName()[:5], sequentialNumber, randomdata.Alphanumeric(10)))
47 | }
48 |
--------------------------------------------------------------------------------
/test/pkg/test/method_match_httproute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | v1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
8 | )
9 |
10 | // creates a route sending GET to getService and POST to postService
11 | func (env *Framework) NewMethodMatchHttpRoute(parentRefsGateway *gwv1.Gateway, getService *v1.Service, postService *v1.Service,
12 | httpRouteName string, namespace string) *gwv1.HTTPRoute {
13 | getRule := gwv1.HTTPRouteRule{
14 | BackendRefs: []gwv1.HTTPBackendRef{{
15 | BackendRef: gwv1.BackendRef{
16 | BackendObjectReference: gwv1.BackendObjectReference{
17 | Name: gwv1.ObjectName(getService.Name),
18 | Kind: lo.ToPtr(gwv1.Kind("Service")),
19 | Port: (*gwv1.PortNumber)(&postService.Spec.Ports[0].Port),
20 | },
21 | },
22 | }},
23 | Matches: []gwv1.HTTPRouteMatch{
24 | {
25 | Method: lo.ToPtr(gwv1.HTTPMethodGet),
26 | },
27 | },
28 | }
29 |
30 | postRule := gwv1.HTTPRouteRule{
31 | BackendRefs: []gwv1.HTTPBackendRef{{
32 | BackendRef: gwv1.BackendRef{
33 | BackendObjectReference: gwv1.BackendObjectReference{
34 | Name: gwv1.ObjectName(postService.Name),
35 | Kind: lo.ToPtr(gwv1.Kind("Service")),
36 | Port: (*gwv1.PortNumber)(&postService.Spec.Ports[0].Port),
37 | },
38 | },
39 | }},
40 | Matches: []gwv1.HTTPRouteMatch{
41 | {
42 | Method: lo.ToPtr(gwv1.HTTPMethodPost),
43 | },
44 | },
45 | }
46 |
47 | httpRoute := New(&gwv1.HTTPRoute{
48 | ObjectMeta: metav1.ObjectMeta{
49 | Name: httpRouteName,
50 | Namespace: namespace,
51 | },
52 | Spec: gwv1.HTTPRouteSpec{
53 | CommonRouteSpec: gwv1.CommonRouteSpec{
54 | ParentRefs: []gwv1.ParentReference{{
55 | Name: gwv1.ObjectName(parentRefsGateway.Name),
56 | SectionName: lo.ToPtr(gwv1.SectionName("http")),
57 | }},
58 | },
59 | Rules: []gwv1.HTTPRouteRule{getRule, postRule},
60 | },
61 | })
62 |
63 | return httpRoute
64 | }
65 |
--------------------------------------------------------------------------------
/test/pkg/test/path_match_httproute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "strconv"
5 |
6 | "github.com/samber/lo"
7 | corev1 "k8s.io/api/core/v1"
8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | "sigs.k8s.io/controller-runtime/pkg/client"
10 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
11 | )
12 |
13 | func (env *Framework) NewPathMatchHttpRoute(parentRefsGateway *gwv1.Gateway, backendRefObjects []client.Object,
14 | gwListenerSectionName string, name string, namespace string) *gwv1.HTTPRoute {
15 | var rules []gwv1.HTTPRouteRule
16 | var httpns *string
17 | if namespace == "" {
18 | httpns = nil
19 |
20 | } else {
21 | httpns = &namespace
22 | }
23 | for i, object := range backendRefObjects {
24 | var port *gwv1.PortNumber
25 | if svc, ok := object.(*corev1.Service); ok {
26 | pv := gwv1.PortNumber(svc.Spec.Ports[0].Port)
27 | port = &pv
28 | }
29 | rule := gwv1.HTTPRouteRule{
30 | BackendRefs: []gwv1.HTTPBackendRef{{
31 | BackendRef: gwv1.BackendRef{
32 | BackendObjectReference: gwv1.BackendObjectReference{
33 | Name: gwv1.ObjectName(object.GetName()),
34 | Namespace: (*gwv1.Namespace)(httpns),
35 | Kind: lo.ToPtr(gwv1.Kind(object.GetObjectKind().GroupVersionKind().Kind)),
36 | Port: port,
37 | },
38 | },
39 | }},
40 | Matches: []gwv1.HTTPRouteMatch{
41 | {
42 | Path: &gwv1.HTTPPathMatch{
43 | Type: lo.ToPtr(gwv1.PathMatchPathPrefix),
44 | Value: lo.ToPtr("/pathmatch" + strconv.Itoa(i)),
45 | },
46 | },
47 | },
48 | }
49 | rules = append(rules, rule)
50 | }
51 |
52 | httpRoute := New(&gwv1.HTTPRoute{
53 | ObjectMeta: metav1.ObjectMeta{
54 | Name: name,
55 | Namespace: namespace,
56 | },
57 | Spec: gwv1.HTTPRouteSpec{
58 | CommonRouteSpec: gwv1.CommonRouteSpec{
59 | ParentRefs: []gwv1.ParentReference{{
60 | Name: gwv1.ObjectName(parentRefsGateway.Name),
61 | Namespace: (*gwv1.Namespace)(httpns),
62 | SectionName: lo.ToPtr(gwv1.SectionName(gwListenerSectionName)),
63 | }},
64 | },
65 | Rules: rules,
66 | },
67 | })
68 | return httpRoute
69 | }
70 |
--------------------------------------------------------------------------------
/test/pkg/test/target_group_policy.go:
--------------------------------------------------------------------------------
1 | package test
2 |
--------------------------------------------------------------------------------
/test/pkg/test/tlsroute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
7 | "sigs.k8s.io/gateway-api/apis/v1alpha2"
8 | )
9 |
10 | func (env *Framework) NewTLSRoute(namespace string, parentRefsGateway *gwv1.Gateway, rules []v1alpha2.TLSRouteRule) *v1alpha2.TLSRoute {
11 | tlsRoute := New(&v1alpha2.TLSRoute{
12 | TypeMeta: metav1.TypeMeta{},
13 | ObjectMeta: metav1.ObjectMeta{
14 | Namespace: namespace,
15 | },
16 | Spec: v1alpha2.TLSRouteSpec{
17 | CommonRouteSpec: v1alpha2.CommonRouteSpec{
18 | ParentRefs: []gwv1.ParentReference{{
19 | Name: gwv1.ObjectName(parentRefsGateway.Name),
20 | Namespace: (*gwv1.Namespace)(&parentRefsGateway.Namespace),
21 | SectionName: lo.ToPtr(gwv1.SectionName("tls")),
22 | }},
23 | },
24 | Hostnames: []gwv1.Hostname{"lattice-k8s-tls-passthrough-test.com"},
25 | Rules: rules,
26 | },
27 | })
28 |
29 | return tlsRoute
30 | }
31 |
--------------------------------------------------------------------------------
/test/pkg/test/weighted_routing_httproute.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/samber/lo"
5 | corev1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | "sigs.k8s.io/controller-runtime/pkg/client"
8 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
9 | )
10 |
11 | type ObjectAndWeight struct {
12 | Object client.Object
13 | Weight int32
14 | }
15 |
16 | func (env *Framework) NewWeightedRoutingHttpRoute(parentRefsGateway *gwv1.Gateway, backendRefObjectAndWeights []*ObjectAndWeight,
17 | gwListenerSectionNames []string) *gwv1.HTTPRoute {
18 |
19 | var backendRefs []gwv1.HTTPBackendRef
20 | for _, objectAndWeight := range backendRefObjectAndWeights {
21 | var port *gwv1.PortNumber
22 | if svc, ok := objectAndWeight.Object.(*corev1.Service); ok {
23 | pv := gwv1.PortNumber(svc.Spec.Ports[0].Port)
24 | port = &pv
25 | }
26 | backendRefs = append(backendRefs, gwv1.HTTPBackendRef{
27 | BackendRef: gwv1.BackendRef{
28 | BackendObjectReference: gwv1.BackendObjectReference{
29 | Name: gwv1.ObjectName(objectAndWeight.Object.GetName()),
30 | Kind: lo.ToPtr(gwv1.Kind(objectAndWeight.Object.GetObjectKind().GroupVersionKind().Kind)),
31 | Port: port,
32 | },
33 | Weight: lo.ToPtr(objectAndWeight.Weight),
34 | },
35 | })
36 | }
37 | var parentRefs []gwv1.ParentReference
38 | for _, gwListenerSectionName := range gwListenerSectionNames {
39 | parentRefs = append(parentRefs, gwv1.ParentReference{
40 | Name: gwv1.ObjectName(parentRefsGateway.Name),
41 | SectionName: lo.ToPtr(gwv1.SectionName(gwListenerSectionName)),
42 | })
43 | }
44 | httpRoute := New(&gwv1.HTTPRoute{
45 | ObjectMeta: metav1.ObjectMeta{
46 | Namespace: parentRefsGateway.Namespace,
47 | },
48 | Spec: gwv1.HTTPRouteSpec{
49 | CommonRouteSpec: gwv1.CommonRouteSpec{
50 | ParentRefs: parentRefs,
51 | },
52 | Rules: []gwv1.HTTPRouteRule{
53 | {
54 | BackendRefs: backendRefs,
55 | },
56 | },
57 | },
58 | })
59 | return httpRoute
60 | }
61 |
--------------------------------------------------------------------------------
/test/suites/integration/readiness_gate_test.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "github.com/aws/aws-application-networking-k8s/pkg/deploy/lattice"
5 | "github.com/aws/aws-application-networking-k8s/pkg/k8s"
6 | "github.com/aws/aws-application-networking-k8s/pkg/utils"
7 | "github.com/aws/aws-application-networking-k8s/test/pkg/test"
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 | "github.com/samber/lo"
11 | appsv1 "k8s.io/api/apps/v1"
12 | v1 "k8s.io/api/core/v1"
13 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
14 | )
15 |
16 | var _ = Describe("Pod Readiness Gate", Ordered, func() {
17 | var (
18 | deployment *appsv1.Deployment
19 | service *v1.Service
20 | route *gwv1.HTTPRoute
21 | )
22 |
23 | BeforeAll(func() {
24 | deployment, service = testFramework.NewNginxApp(test.ElasticSearchOptions{
25 | Name: "pod-test",
26 | Namespace: k8snamespace,
27 | ReadinessGate: true,
28 | })
29 | route = testFramework.NewHttpRoute(testGateway, service, service.Kind)
30 | testFramework.ExpectCreated(ctx, deployment, service, route)
31 | })
32 |
33 | It("updates condition when injected", func() {
34 | Eventually(func(g Gomega) {
35 | pods := testFramework.GetPodsByDeploymentName(deployment.Name, deployment.Namespace)
36 | for _, pod := range pods {
37 | cond := utils.FindPodStatusCondition(pod.Status.Conditions, lattice.LatticeReadinessGateConditionType)
38 | g.Expect(cond).To(Not(BeNil()))
39 | g.Expect(cond.Status).To(Equal(v1.ConditionTrue))
40 | }
41 | }).Should(Succeed())
42 | })
43 |
44 | It("updates condition when a new pod is added", func() {
45 | testFramework.Get(ctx, k8s.NamespacedName(deployment), deployment)
46 | deployment.Spec.Replicas = lo.ToPtr(int32(3))
47 | testFramework.ExpectUpdated(ctx, deployment)
48 |
49 | Eventually(func(g Gomega) {
50 | pods := testFramework.GetPodsByDeploymentName(deployment.Name, deployment.Namespace)
51 | for _, pod := range pods {
52 | cond := utils.FindPodStatusCondition(pod.Status.Conditions, lattice.LatticeReadinessGateConditionType)
53 | g.Expect(cond).To(Not(BeNil()))
54 | g.Expect(cond.Status).To(Equal(v1.ConditionTrue))
55 | }
56 | }).Should(Succeed())
57 | })
58 |
59 | AfterAll(func() {
60 | testFramework.ExpectDeletedThenNotFound(ctx,
61 | deployment,
62 | service,
63 | route,
64 | )
65 | })
66 | })
67 |
--------------------------------------------------------------------------------
/test/suites/webhook/suite_test.go:
--------------------------------------------------------------------------------
1 | package webhook
2 |
3 | import (
4 | "context"
5 | "github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
6 | "github.com/aws/aws-application-networking-k8s/test/pkg/test"
7 | "github.com/aws/aws-sdk-go/service/vpclattice"
8 | . "github.com/onsi/ginkgo/v2"
9 | . "github.com/onsi/gomega"
10 | "go.uber.org/zap"
11 | "os"
12 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
13 | "testing"
14 | )
15 |
16 | const (
17 | k8snamespace = "webhook-" + test.K8sNamespace
18 | )
19 |
20 | var testFramework *test.Framework
21 | var ctx context.Context
22 | var testGateway *gwv1.Gateway
23 | var testServiceNetwork *vpclattice.ServiceNetworkSummary
24 |
25 | var _ = SynchronizedBeforeSuite(func() {
26 | vpcId := os.Getenv("CLUSTER_VPC_ID")
27 | if vpcId == "" {
28 | Fail("CLUSTER_VPC_ID environment variable must be set to run integration tests")
29 | }
30 |
31 | // provision gateway, wait for service network association
32 | testGateway = testFramework.NewGateway("test-gateway", k8snamespace)
33 | testFramework.ExpectCreated(ctx, testGateway)
34 |
35 | testServiceNetwork = testFramework.GetServiceNetwork(ctx, testGateway)
36 |
37 | testFramework.Log.Infof(ctx, "Expecting VPC %s and service network %s association", vpcId, *testServiceNetwork.Id)
38 | Eventually(func(g Gomega) {
39 | associated, _, _ := testFramework.IsVpcAssociatedWithServiceNetwork(ctx, vpcId, testServiceNetwork)
40 | g.Expect(associated).To(BeTrue())
41 | }).Should(Succeed())
42 | }, func() {
43 | testGateway = testFramework.NewGateway("test-gateway", k8snamespace)
44 | testServiceNetwork = testFramework.GetServiceNetwork(ctx, testGateway)
45 | })
46 |
47 | func TestIntegration(t *testing.T) {
48 | ctx = test.NewContext(t)
49 | logger := gwlog.NewLogger(zap.DebugLevel)
50 | testFramework = test.NewFramework(ctx, logger, k8snamespace)
51 | RegisterFailHandler(Fail)
52 | RunSpecs(t, "WebhookIntegration")
53 | }
54 |
55 | var _ = SynchronizedAfterSuite(func() {}, func() {
56 | testFramework.ExpectDeletedThenNotFound(ctx, testGateway)
57 | })
58 |
--------------------------------------------------------------------------------