├── .build ├── build-e2e-only.yaml ├── build-openresty.yaml └── build.yaml ├── .cspell.json ├── .dockerignore ├── .editorconfig ├── .github ├── chart │ └── alb │ │ └── values.yaml ├── cr.sh ├── cr.yaml └── workflows │ ├── alb-perf.yaml │ ├── build-openresty.yaml │ └── build.yaml ├── .gitignore ├── .golangci.yml ├── .lua-format ├── .luacheckrc ├── .luacov ├── .luarc.json ├── .vscode ├── README.md └── launch.json ├── Dockerfile ├── LICENSE.txt ├── README.md ├── catalog └── alb.yaml ├── cmd ├── alb │ └── main.go ├── operator │ └── main.go └── utils │ ├── albctl │ ├── cmd │ │ ├── debug.go │ │ ├── log_analyze.go │ │ ├── log_analyze_test.go │ │ ├── root.go │ │ ├── rule.go │ │ └── rule_test.go │ └── main.go │ ├── dirhash │ └── main.go │ ├── map_gen │ └── main.go │ ├── ngx_gen │ └── main.go │ ├── sync_rbac │ └── main.go │ ├── tweak_gen │ └── main.go │ └── tylua │ └── main.go ├── config ├── config.go ├── config_ext.go ├── gateway.go ├── mock_config.go └── types.go ├── controller ├── alb │ └── alb.go ├── alb2.go ├── cli │ ├── alb.go │ ├── cert.go │ ├── cert_test.go │ ├── policy.go │ ├── policy_backend.go │ ├── policy_l4.go │ └── policy_l7.go ├── common.go ├── controller_test.go ├── leader.go ├── leader_test.go ├── modules │ ├── alb2.go │ └── consts.go ├── nginx.go ├── nginx_test.go ├── patrol.go ├── policy_zip.go ├── portprobe.go ├── portprobe_test.go ├── state │ └── state.go ├── sync_lb_service.go └── types │ ├── consts.go │ ├── helper.go │ ├── policyext_test.go │ └── types.go ├── deploy ├── README.md ├── chart │ └── alb │ │ ├── Chart.yaml │ │ ├── crds │ │ ├── crd.alauda.io_alaudaloadbalancer2.yaml │ │ ├── crd.alauda.io_frontends.yaml │ │ ├── crd.alauda.io_rules.yaml │ │ ├── gateway.crd.alauda.io_timeoutpolicies.yaml │ │ └── gateway │ │ │ ├── gateway.networking.k8s.io_backendtlspolicies.yaml │ │ │ ├── gateway.networking.k8s.io_gatewayclasses.yaml │ │ │ ├── gateway.networking.k8s.io_gateways.yaml │ │ │ ├── gateway.networking.k8s.io_grpcroutes.yaml │ │ │ ├── gateway.networking.k8s.io_httproutes.yaml │ │ │ ├── gateway.networking.k8s.io_referencegrants.yaml │ │ │ ├── gateway.networking.k8s.io_tcproutes.yaml │ │ │ ├── gateway.networking.k8s.io_tlsroutes.yaml │ │ │ └── gateway.networking.k8s.io_udproutes.yaml │ │ ├── module-plugin.yaml │ │ ├── scripts │ │ └── plugin-config.yaml │ │ ├── templates │ │ ├── acp_dashborad.yaml │ │ ├── alb.featuregate.yaml │ │ ├── alb.yaml │ │ ├── deploy-deployment.yaml │ │ ├── loadbalancer-service.featuregate.yaml │ │ ├── operator-clusterrole.yaml │ │ ├── operator-clusterrolebinding.yaml │ │ └── operator-sa.yaml │ │ └── values.yaml └── resource │ ├── dashboard │ └── alb-overview.json │ └── rbac │ └── operator-clusterrole.yaml ├── docs ├── README.md ├── _res │ ├── architecture.png │ └── common-app.yaml ├── dev-readme.md ├── feature │ ├── auth │ │ ├── _res │ │ │ ├── auth-resty.template │ │ │ └── basic-auth.svg │ │ ├── auth-eng.md │ │ ├── auth.md │ │ ├── dev_readme.md │ │ ├── 测试用例.md │ │ └── 配置oauth2-proxy.md │ ├── containermode │ │ └── api-containermode-gateway-deploy.md │ ├── errorpage │ │ └── errorpage.md │ ├── ingressclass │ │ └── api-ingressclass.md │ ├── keepalive │ │ ├── app.yaml │ │ └── testcase.md │ ├── modsecurity │ │ ├── modsecurity.en.md │ │ └── modsecurity.md │ ├── otel │ │ ├── _res │ │ │ ├── alb-otel.drawio.svg │ │ │ ├── jaeger.png │ │ │ └── trace.png │ │ └── otel.md │ ├── redirect │ │ ├── app.yaml │ │ └── testcase.md │ ├── rule │ │ └── rules.md │ └── timeout │ │ ├── app.yaml │ │ └── testcase.md ├── flags │ └── cert.md └── release-note │ └── README.md ├── driver ├── alb2.go ├── constants.go ├── driver.go ├── driver_test.go ├── informers.go └── kubernetes.go ├── gateway ├── constant.go ├── ctl │ ├── common_filter.go │ ├── constants.go │ ├── driver.go │ ├── gateway.go │ ├── gateway_class.go │ ├── hostname_filter.go │ ├── hostname_filter_test.go │ ├── reservedPortFilter.go │ ├── setup.go │ ├── types.go │ ├── util.go │ ├── watches_alb.go │ └── watches_router.go ├── nginx │ ├── driver.go │ ├── http │ │ ├── httproute.go │ │ ├── httproute_filter.go │ │ ├── httproute_filter_test.go │ │ ├── httproute_test.go │ │ └── utils.go │ ├── nginx.go │ ├── policyattachment │ │ ├── common.go │ │ ├── manager.go │ │ ├── timeout_policy.go │ │ ├── timeout_policy_test.go │ │ └── types │ │ │ └── types.go │ ├── tcp.go │ ├── types │ │ └── types.go │ ├── udp.go │ └── utils │ │ └── utils.go ├── utils.go └── utils │ └── hostname.go ├── go.mod ├── go.sum ├── ingress ├── const.go ├── driver.go ├── ingress_controller.go ├── ingress_select.go ├── ingress_status.go ├── ingress_status_test.go ├── ingress_sync.go ├── ingress_sync_test.go ├── ingress_test.go ├── need.go ├── project.go ├── resync.go ├── resync_test.go ├── util.go └── util │ ├── util.go │ └── util_test.go ├── migrate ├── backup │ └── backup.sh ├── checklist │ ├── README.md │ ├── custom │ │ ├── alb │ │ │ └── check_cm │ │ │ │ └── cm_map │ │ │ │ ├── v3.0 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream │ │ │ │ └── upstream │ │ │ │ ├── v3.10 │ │ │ │ ├── grpc_server │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream-common │ │ │ │ ├── stream-tcp │ │ │ │ ├── stream-udp │ │ │ │ └── upstream │ │ │ │ ├── v3.4 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream │ │ │ │ └── upstream │ │ │ │ ├── v3.6.0 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream │ │ │ │ └── upstream │ │ │ │ ├── v3.6.9 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream │ │ │ │ └── upstream │ │ │ │ ├── v3.8.0 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream-common │ │ │ │ ├── stream-tcp │ │ │ │ ├── stream-udp │ │ │ │ └── upstream │ │ │ │ └── v3.8.13 │ │ │ │ ├── http │ │ │ │ ├── http_server │ │ │ │ ├── stream-common │ │ │ │ ├── stream-tcp │ │ │ │ ├── stream-udp │ │ │ │ └── upstream │ │ └── check-alb.sh │ ├── helper.sh │ ├── run.sh │ └── test.sh ├── init-port-info │ ├── README.md │ └── main.go ├── priority │ ├── README.md │ └── main.go └── v26tov28 │ ├── README.md │ └── main.go ├── pkg ├── apis │ └── alauda │ │ ├── gateway │ │ └── v1alpha1 │ │ │ ├── doc.go │ │ │ ├── register.go │ │ │ ├── types.go │ │ │ └── zz_generated.deepcopy.go │ │ ├── shared │ │ ├── cr.go │ │ └── zz_generated.deepcopy.go │ │ ├── v1 │ │ ├── doc.go │ │ ├── register.go │ │ ├── types.go │ │ └── zz_generated.deepcopy.go │ │ └── v2beta1 │ │ ├── alb2_types.go │ │ ├── doc.go │ │ ├── groupversion_info.go │ │ └── zz_generated.deepcopy.go ├── client │ ├── clientset │ │ └── versioned │ │ │ ├── clientset.go │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── clientset_generated.go │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ ├── scheme │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ └── typed │ │ │ ├── alauda │ │ │ ├── v1 │ │ │ │ ├── alauda_client.go │ │ │ │ ├── alb2.go │ │ │ │ ├── doc.go │ │ │ │ ├── fake │ │ │ │ │ ├── doc.go │ │ │ │ │ ├── fake_alauda_client.go │ │ │ │ │ ├── fake_alb2.go │ │ │ │ │ ├── fake_frontend.go │ │ │ │ │ └── fake_rule.go │ │ │ │ ├── frontend.go │ │ │ │ ├── generated_expansion.go │ │ │ │ └── rule.go │ │ │ └── v2beta1 │ │ │ │ ├── alauda_client.go │ │ │ │ ├── alb2.go │ │ │ │ ├── doc.go │ │ │ │ ├── fake │ │ │ │ ├── doc.go │ │ │ │ ├── fake_alauda_client.go │ │ │ │ └── fake_alb2.go │ │ │ │ └── generated_expansion.go │ │ │ └── gateway │ │ │ └── v1alpha1 │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── doc.go │ │ │ ├── fake_gateway_client.go │ │ │ └── fake_timeoutpolicy.go │ │ │ ├── gateway_client.go │ │ │ ├── generated_expansion.go │ │ │ └── timeoutpolicy.go │ ├── informers │ │ └── externalversions │ │ │ ├── alauda │ │ │ ├── interface.go │ │ │ ├── v1 │ │ │ │ ├── alb2.go │ │ │ │ ├── frontend.go │ │ │ │ ├── interface.go │ │ │ │ └── rule.go │ │ │ └── v2beta1 │ │ │ │ ├── alb2.go │ │ │ │ └── interface.go │ │ │ ├── factory.go │ │ │ ├── gateway │ │ │ ├── interface.go │ │ │ └── v1alpha1 │ │ │ │ ├── interface.go │ │ │ │ └── timeoutpolicy.go │ │ │ ├── generic.go │ │ │ └── internalinterfaces │ │ │ └── factory_interfaces.go │ └── listers │ │ ├── alauda │ │ ├── v1 │ │ │ ├── alb2.go │ │ │ ├── expansion_generated.go │ │ │ ├── frontend.go │ │ │ └── rule.go │ │ └── v2beta1 │ │ │ ├── alb2.go │ │ │ └── expansion_generated.go │ │ └── gateway │ │ └── v1alpha1 │ │ ├── expansion_generated.go │ │ └── timeoutpolicy.go ├── config │ ├── albrun.go │ └── const.go ├── controller │ ├── ext │ │ ├── auth │ │ │ ├── auth.go │ │ │ ├── auth_test.go │ │ │ ├── basic_auth.go │ │ │ ├── forward_auth.go │ │ │ ├── types │ │ │ │ ├── codegen_mapping.go │ │ │ │ ├── types.go │ │ │ │ └── zz_generated.deepcopy.go │ │ │ └── util.go │ │ ├── keepalive │ │ │ ├── keepalive.go │ │ │ ├── test │ │ │ │ └── keepalive_test.go │ │ │ └── types │ │ │ │ ├── types.go │ │ │ │ └── zz_generated.deepcopy.go │ │ ├── otel │ │ │ ├── otel.go │ │ │ ├── test │ │ │ │ └── otel_test.go │ │ │ └── types │ │ │ │ ├── type.go │ │ │ │ └── zz_generated.deepcopy.go │ │ ├── redirect │ │ │ ├── redirect.go │ │ │ ├── test │ │ │ │ └── redirect_test.go │ │ │ └── types │ │ │ │ ├── codegen_mapping.go │ │ │ │ ├── type.go │ │ │ │ └── zz_generated.deepcopy.go │ │ ├── timeout │ │ │ ├── test │ │ │ │ └── timeout_test.go │ │ │ ├── timeout.go │ │ │ └── types │ │ │ │ ├── codegen_mapping.go │ │ │ │ ├── type.go │ │ │ │ └── zz_generated.deepcopy.go │ │ └── waf │ │ │ ├── test │ │ │ └── waf_test.go │ │ │ ├── types │ │ │ ├── waf_type.go │ │ │ └── zz_generated.deepcopy.go │ │ │ └── waf.go │ ├── extctl │ │ ├── extctl.go │ │ ├── extctl_test.go │ │ ├── header_moidy_ctl.go │ │ ├── header_moidy_ctl_test.go │ │ ├── legacy.go │ │ └── types │ │ │ └── type.go │ └── ngxconf │ │ ├── nginx.tmpl │ │ ├── nginx_param.go │ │ ├── ngxconf.go │ │ ├── ngxconf_tmpl.go │ │ ├── ngxconf_tmpl_test.go │ │ ├── test │ │ └── ngxconf_test.go │ │ └── types │ │ └── types.go ├── operator │ ├── .dockerignore │ ├── .gitignore │ ├── config │ │ ├── config_test.go │ │ ├── const.go │ │ ├── external.go │ │ ├── external_test.go │ │ ├── internal.go │ │ └── operator.go │ ├── controllers │ │ ├── depl │ │ │ ├── alb_cli.go │ │ │ ├── alb_overwrite_configmap.go │ │ │ ├── alb_reconciler.go │ │ │ ├── alb_status.go │ │ │ ├── current.go │ │ │ ├── depl_ctl.go │ │ │ ├── depl_test.go │ │ │ ├── handle_backup_annotation.go │ │ │ ├── patch │ │ │ │ ├── configmap_patch.go │ │ │ │ └── image_patch.go │ │ │ ├── resources │ │ │ │ ├── configmap │ │ │ │ │ ├── configmap.go │ │ │ │ │ ├── const.go │ │ │ │ │ └── options.go │ │ │ │ ├── feature │ │ │ │ │ └── feature.go │ │ │ │ ├── gateway │ │ │ │ │ ├── gatewayclass.go │ │ │ │ │ └── options.go │ │ │ │ ├── ingressclass │ │ │ │ │ ├── ingcls_ctl.go │ │ │ │ │ └── ingcls_ctl_test.go │ │ │ │ ├── portinfo │ │ │ │ │ ├── options.go │ │ │ │ │ └── portinfo.go │ │ │ │ ├── rbac │ │ │ │ │ ├── alb-clusterrole.json │ │ │ │ │ ├── rbac.go │ │ │ │ │ └── rbac_test.go │ │ │ │ ├── service │ │ │ │ │ ├── svcctl.go │ │ │ │ │ └── svcctl_test.go │ │ │ │ ├── types │ │ │ │ │ └── types.go │ │ │ │ └── workload │ │ │ │ │ ├── deploy.go │ │ │ │ │ ├── deploy_test.go │ │ │ │ │ └── options.go │ │ │ ├── suite_test.go │ │ │ └── util │ │ │ │ └── util.go │ │ ├── init.go │ │ ├── scheme.go │ │ ├── setup.go │ │ ├── standalone_gateway │ │ │ ├── gateway │ │ │ │ ├── cli_ext.go │ │ │ │ └── reconciler.go │ │ │ └── gatewayclass │ │ │ │ └── reconciler.go │ │ ├── suite_test.go │ │ └── types │ │ │ └── const.go │ └── toolkit │ │ ├── clustertype.go │ │ ├── meta.go │ │ ├── tools.go │ │ └── tools_test.go └── utils │ ├── data_trans.go │ ├── metrics │ └── metrics.go │ ├── test_utils │ ├── ing_utils │ │ └── ing.go │ ├── mock_svc.go │ ├── ngx_conf.go │ ├── ngxconf_parser_ext_test.go │ ├── policy_assert.go │ └── policy_helper.go │ └── util.go ├── run-alb.sh ├── scripts ├── alb-ai-actions.sh ├── alb-build-actions.sh ├── alb-checklist-actions.sh ├── alb-codegen-actions.sh ├── alb-debug-actions.sh ├── alb-dev-actions.sh ├── alb-env-actions.sh ├── alb-github-actions.sh ├── alb-lint-actions.sh ├── alb-perf-actions.sh ├── alb-test-actions.sh ├── boilerplate.go.txt ├── custom-ci-action.sh ├── go-test.sh ├── kubescape.js ├── nginx-test.sh ├── rule-gen.py ├── run-like-ci-go.sh ├── run-like-ci-kind.sh ├── run-like-ci-nginx.sh ├── run-like-github-actions.sh ├── tmuxs │ └── fg.tmux.json └── yaml │ └── crds │ ├── extra │ ├── mock │ │ ├── cluster.yaml │ │ └── clustercert.yaml │ ├── v1 │ │ ├── apprelease.yaml │ │ ├── csv.crd.yaml │ │ ├── features.crd.yaml │ │ └── hr.crd.yaml │ └── v1beta1 │ │ └── features.crd.yaml │ ├── v1 │ └── alb │ │ ├── crd.alauda.io_alaudaloadbalancer2.yaml │ │ ├── crd.alauda.io_frontends.yaml │ │ └── crd.alauda.io_rules.yaml │ └── v1beta1 │ ├── alb2-crd.yaml │ ├── features.crd.yaml │ ├── frontend-crd.yaml │ └── rule-crd.yaml ├── sonar-project.properties ├── template ├── Dockerfile.debug ├── Dockerfile.openresty ├── README.md ├── actions │ ├── alb-nginx-install-deps.sh │ ├── alb-nginx.sh │ ├── dev.actions.sh │ └── test-nginx-in-ci.sh ├── chaos │ ├── break │ │ ├── README.md │ │ ├── alb.nginx.conf │ │ ├── policy.json │ │ └── server.py │ └── tl502 │ │ ├── README.md │ │ ├── demo.conf │ │ ├── server.py │ │ ├── test.lua │ │ ├── test.t │ │ └── x.lua ├── nginx │ ├── lua │ │ ├── README.md │ │ ├── balancer │ │ │ ├── alb_chash.lua │ │ │ ├── balance.lua │ │ │ ├── common.lua │ │ │ ├── resty.lua │ │ │ ├── round_robin.lua │ │ │ ├── sticky.lua │ │ │ └── sticky_balanced.lua │ │ ├── cert_tool.lua │ │ ├── config │ │ │ ├── README.md │ │ │ ├── cache.lua │ │ │ ├── conf.lua │ │ │ ├── policy_fetch.lua │ │ │ └── shmap.lua │ │ ├── cors.lua │ │ ├── ctx │ │ │ ├── alb_ctx.lua │ │ │ └── var_proxy.lua │ │ ├── error.lua │ │ ├── l4_preread.lua │ │ ├── l7_redirect.lua │ │ ├── match_engine │ │ │ ├── dsl.lua │ │ │ ├── operation.lua │ │ │ └── upstream.lua │ │ ├── metrics.lua │ │ ├── metrics_auth.lua │ │ ├── phase │ │ │ ├── balancer_phase.lua │ │ │ ├── init_worker_phase.lua │ │ │ ├── l7_header_filter_phase.lua │ │ │ ├── l7_rewrite_phase.lua │ │ │ ├── log_phase.lua │ │ │ └── ssl_cert_phase.lua │ │ ├── plugins │ │ │ ├── auth │ │ │ │ ├── auth.lua │ │ │ │ ├── basic_auth.lua │ │ │ │ ├── buffer_md5.lua │ │ │ │ ├── crypt.lua │ │ │ │ └── forward_auth.lua │ │ │ ├── core │ │ │ │ └── plugin_manager.lua │ │ │ ├── otel │ │ │ │ ├── otel.lua │ │ │ │ ├── tool.lua │ │ │ │ ├── tracer.lua │ │ │ │ └── tracer_http_client.lua │ │ │ └── timeout.lua │ │ ├── replace_prefix_match.lua │ │ ├── rewrite_header.lua │ │ ├── types │ │ │ ├── common.lua │ │ │ ├── ngxpolicy.types.lua │ │ │ └── vendor.lua │ │ ├── utils │ │ │ ├── common.lua │ │ │ ├── compress.lua │ │ │ ├── generic_ext.lua │ │ │ ├── ip.lua │ │ │ ├── numer_ext.lua │ │ │ ├── string_ext.lua │ │ │ ├── subsystem.lua │ │ │ └── url.lua │ │ └── vendor │ │ │ ├── events.lua │ │ │ ├── lua-ffi-zlib │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── dist.ini │ │ │ ├── lib │ │ │ │ └── ffi-zlib.lua │ │ │ ├── lua-ffi-zlib-0.4-0.rockspec │ │ │ ├── lua-ffi-zlib-0.5-0.rockspec │ │ │ └── test.lua │ │ │ └── prometheus │ │ │ ├── prometheus.lua │ │ │ ├── prometheus_keys.lua │ │ │ └── prometheus_resty_counter.lua │ ├── nginx.conf │ ├── policy.example.json │ └── run-nginx.sh └── t │ ├── Alauda.pm │ ├── AlaudaLib.pm │ ├── AlaudaTest.pm │ ├── balancer.t │ ├── balancer_test.lua │ ├── common.t │ ├── cors.t │ ├── e2e │ ├── auth_test │ │ ├── auth_test.lua │ │ └── auth_test.t │ ├── cert │ │ ├── cert.lua │ │ └── cert.t │ ├── error_page │ │ ├── error.lua │ │ └── error.t │ ├── https_upgrade │ │ ├── test.lua │ │ └── test.t │ ├── metrics │ │ ├── metrics.lua │ │ └── metrics.t │ ├── ping │ │ ├── ping.lua │ │ └── ping.t │ ├── retry_test │ │ ├── retry_test.lua │ │ └── retry_test.t │ ├── rewrite_request │ │ ├── test.lua │ │ └── test.t │ ├── rule_match │ │ ├── rule.lua │ │ └── rule.t │ ├── timeout_test │ │ ├── timeout_test.lua │ │ └── timeout_test.t │ ├── trace │ │ ├── trace.lua │ │ └── trace.t │ └── waf │ │ ├── waf.lua │ │ └── waf.t │ ├── l7_redirect.t │ ├── lib │ ├── F.lua │ ├── inspect.lua │ ├── mock_worker_init.lua │ ├── policy_helper.lua │ ├── test-helper.lua │ └── util.lua │ ├── manually │ ├── fortio │ │ ├── fortio.lua │ │ └── fortio.perf │ ├── nyi │ │ ├── nyi │ │ └── nyi.lua │ └── otel_test │ │ ├── otel_test │ │ └── otel_test.lua │ ├── matches.t │ ├── nignx_config.t │ ├── ping.t │ ├── proxy-paas-between-https-and-http.t │ ├── resource │ ├── policy.bin │ ├── policy.bin.empty │ └── policy.bin.invalid │ ├── rewrite_response.t │ ├── timeout.ignore │ ├── udp.t │ ├── unit │ ├── cert_test.lua │ ├── common_test.lua │ ├── cors_test.lua │ ├── plugins │ │ └── auth │ │ │ └── auth_unit_test.lua │ ├── replace_prefix_match_test.lua │ ├── unit_test.lua │ └── unit_test.t │ ├── url_rewrite.t │ └── zip.t ├── test ├── README.md ├── alauda │ └── README.md ├── checklist │ ├── alb.go │ ├── apprelease.yaml │ ├── hr.yaml │ └── suite_test.go ├── conformance │ ├── gatewayapi │ │ └── suite_test.go │ └── ingress-nginx │ │ ├── README.md │ │ ├── auth.go │ │ ├── auth_kind.sh │ │ ├── auth_resty.go │ │ ├── lua_snip │ │ ├── app.lua │ │ ├── auth.lua │ │ └── state.lua │ │ └── suite_test.go ├── e2e │ ├── alb │ │ └── alb.go │ ├── cases │ │ └── cases.go │ ├── framework │ │ ├── alb_assert_ext.go │ │ ├── alb_operator_ext.go │ │ ├── albenv.go │ │ ├── albwaitfile_ext.go │ │ ├── consts.go │ │ ├── gateway_assert_ext.go │ │ ├── ingress_assert_ext.go │ │ ├── operator_env.go │ │ ├── product_ns.go │ │ ├── suite_helper.go │ │ ├── svc_ext_.go │ │ ├── tls.go │ │ └── util.go │ ├── gateway │ │ ├── common.go │ │ ├── http.go │ │ ├── policyattachment │ │ │ └── timeout_policy.go │ │ ├── shared_gateway.go │ │ ├── standalone_gateway.go │ │ ├── tcp.go │ │ └── udp.go │ ├── ingress │ │ ├── all.ingress │ │ ├── ingress.go │ │ └── rule_sync.go │ ├── operator │ │ ├── README.md │ │ ├── alb │ │ │ └── basic.go │ │ ├── gateway │ │ │ └── gateway.go │ │ ├── public-cloud │ │ │ └── cce.go │ │ ├── rawk8s │ │ │ └── raw.go │ │ └── simple │ │ │ ├── basic.go │ │ │ ├── chart.go │ │ │ ├── operator.go │ │ │ ├── patch.go │ │ │ └── update.go │ ├── perf │ │ └── perf.go │ ├── rule-perf-cpu │ └── suite_test.go └── kind │ ├── e2e │ ├── gateway │ │ └── gateway.go │ ├── operator │ │ └── operator.go │ ├── qps_test.go │ └── suite_test.go │ └── pkg │ └── helper │ ├── alb-chart-ext.go │ ├── alb-chart-ext_test.go │ ├── alb-ctx.go │ ├── echo-resty-ext.go │ ├── echo-resty.yaml │ ├── echo-resty_test.go │ ├── king-gc.go │ ├── king-gc_test.go │ └── qps │ ├── assert.go │ ├── curl.go │ ├── keep-curl.go │ └── keep-curl_test.go ├── timestamp.txt └── utils ├── address.go ├── client └── client.go ├── consts.go ├── dirhash ├── hash.go └── hash_test.go ├── dsl.go ├── dsl_test.go ├── log ├── log.go └── log_test.go ├── net_utils.go ├── string_ext.go ├── string_ext_test.go ├── test_utils ├── assert │ ├── alb.go │ ├── deployment.go │ └── ingress.go ├── assert_cr_helper.go ├── command.go ├── console_logger.go ├── docker-ext.go ├── docker-ext_test.go ├── envtest_ext.go ├── eq.go ├── fake_alb_env.go ├── fake_alb_env_test.go ├── faker.go ├── ginkgo_ext.go ├── ginkgo_logger.go ├── helm_ext.go ├── initer.go ├── json.go ├── k8s_client_ext.go ├── kind-ext.go ├── kind-ext_test.go ├── kubectl_ext.go ├── metallb_ext.go ├── mocklbsvc.go ├── util.go ├── util_test.go ├── yq.go └── yq_test.go ├── types.go ├── util.go ├── wait.go └── wait_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | alauda_lb 3 | alauda_lb.iml 4 | .git/test/e2e/viper-config.toml 5 | -------------------------------------------------------------------------------- /.github/chart/alb/values.yaml: -------------------------------------------------------------------------------- 1 | ## global 2 | operator: 3 | albImagePullPolicy: IfNotPresent 4 | defaultAlb: false # 部署默认的alb 5 | operatorReplicas: 1 6 | operatorDeployMode: "deployment" # csv|deployment 7 | global: 8 | labelBaseDomain: cpaas.io 9 | namespace: kube-system 10 | registry: 11 | address: theseedoaa 12 | images: 13 | alb2: 14 | code: https://github.com/alauda/alb 15 | support_arm: true 16 | repository: alb 17 | nginx: 18 | code: https://github.com/alauda/alb 19 | support_arm: true 20 | repository: alb 21 | resources: 22 | alb: 23 | limits: 24 | cpu: "200m" 25 | memory: 2Gi 26 | requests: 27 | cpu: 50m 28 | memory: 128Mi 29 | limits: 30 | cpu: "2" 31 | memory: 2Gi 32 | requests: 33 | cpu: 50m 34 | memory: 128Mi 35 | -------------------------------------------------------------------------------- /.github/cr.yaml: -------------------------------------------------------------------------------- 1 | sign: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Example user template template 3 | ### Example user template 4 | 5 | # IntelliJ project files 6 | .idea 7 | *.iml 8 | out 9 | gen 10 | config/haproxy/* 11 | alb2 12 | migrate_priority 13 | migrate_v26tov28 14 | *.DS_Store 15 | haproxy.cfg.new 16 | policy.new 17 | VERSION 18 | test.json 19 | coverage-all.out 20 | alb-nginx/luacov.stats.out 21 | temp/ 22 | .wc/ 23 | scripts/e2e/.tmp 24 | .scannerwork 25 | alb-nginx/t/servroot 26 | alb-nginx/t/.nvimlog 27 | tweak 28 | scripts/loop.sh 29 | alb-nginx/actions/loop.sh 30 | bin 31 | .alb.local 32 | test/e2e/alb-config.toml 33 | *.log 34 | .vscode/settings.json 35 | test/e2e/*.test 36 | test/e2e/*/*.test 37 | test/e2e/*/*/*.test 38 | cmds.cfg 39 | .t/ 40 | loop.sh 41 | alauda-alb2/ 42 | coverage.* 43 | deploy/operator/bundle 44 | deploy/operator/bundle.Dockerfile 45 | .test/ 46 | template/servroot 47 | template/dhparam.pem 48 | template/policy.new 49 | template/nginx/logs 50 | template/logs 51 | template/cert 52 | alb-kind-e2e 53 | test.test 54 | migrate/checklist/.kube/ 55 | kubectl* 56 | fortio/*.json 57 | .flame/ 58 | template/nginx/lua/vendor/opentelemetry 59 | *.kconf 60 | docs/.obsidian 61 | template/share/dhparam.pem 62 | luacov-html/ 63 | luacov.stats.out 64 | luacov.report.out 65 | luacov.report.out.index 66 | luacov.summary 67 | .kube 68 | .fg 69 | .review/ -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 4600s 3 | skip-dirs: 4 | - test 5 | linters: 6 | enable: 7 | - gocritic 8 | - gofumpt 9 | - goimports 10 | - misspell 11 | - predeclared 12 | - revive 13 | - unconvert 14 | - unused 15 | issues: 16 | exclude-rules: 17 | - linters: 18 | - staticcheck 19 | text: "SA1019:" # gateway status deprecated. gv1.GatewayReasonReady is deprecated: Ready is reserved for future use 20 | - path: _test\.go 21 | linters: 22 | - errcheck 23 | linters-settings: 24 | errcheck: 25 | check-blank: true 26 | gocritic: 27 | disabled-checks: 28 | - ifElseChain 29 | - singleCaseSwitch 30 | - badCond 31 | revive: 32 | rules: 33 | - name: var-naming 34 | severity: warning 35 | disabled: true -------------------------------------------------------------------------------- /.lua-format: -------------------------------------------------------------------------------- 1 | use_tab: false 2 | keep_simple_control_block_one_line: false 3 | line-breaks-after-function-body: false 4 | keep_simple_function_one_line: false 5 | column_limit: 380 6 | chop_down_table: true 7 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | std = 'ngx_lua' 2 | codes = true 3 | max_line_length = false 4 | globals = { 5 | 'ngx', 'ndk', 6 | } 7 | ignore= {"411","421","431"} 8 | read_globals = { 9 | "coroutine._yield" 10 | } 11 | exclude_files = {"template/nginx/lua/vendor/**"} -------------------------------------------------------------------------------- /.luacov: -------------------------------------------------------------------------------- 1 | reporter = "html" 2 | html = {} 3 | include = { 4 | ".*/template/nginx/lua/.*" 5 | } 6 | exclude = { 7 | ".*/template/nginx/lua/vendor/.*", 8 | } 9 | -------------------------------------------------------------------------------- /.luarc.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime": { 3 | "version": "Lua 5.1", 4 | "path": [ 5 | "?.lua", 6 | "?/init.lua", 7 | "./template/nginx/lua/?.lua", 8 | "./template/nginx/lua/vendor/?.lua" 9 | ] 10 | }, 11 | "diagnostics": { 12 | "ignoredFiles": "Disable", 13 | "libraryFiles": "Disable", 14 | "globals": [ 15 | "vim", 16 | "use", 17 | "ngx", 18 | "jit", 19 | "_ENV" 20 | ] 21 | }, 22 | "workspace": { 23 | "ignoreDir": [ 24 | ".vscode", 25 | "work-park", 26 | "vendor" 27 | ], 28 | "library": [ 29 | "${3rd}/OpenResty/library" 30 | ] 31 | } 32 | } -------------------------------------------------------------------------------- /.vscode/README.md: -------------------------------------------------------------------------------- 1 | # recommend plugins 2 | ```bash 3 | code --install-extension sumneko.lua 4 | 5 | ``` -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "operator", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "exec", 9 | "env": { 10 | "USE_KUBE_CONFIG": "/home/cong/.kube/gw", 11 | "LEADER_NS": "cpaas-system", 12 | "ALB_IMAGE": "registry.alauda.cn:60080/acp/alb2:v3.14.1", 13 | "NGINX_IMAGE": "registry.alauda.cn:60080/acp/alb-nginx:v3.14.1", 14 | "VERSION": "v3.14.1", 15 | "LABEL_BASE_DOMAIN": "cpaas.io", 16 | }, 17 | "program": "operator" 18 | }, 19 | { 20 | // use FIT to focus 21 | "name": "ginkgo envtest", 22 | "type": "go", 23 | "request": "launch", 24 | "mode": "test", 25 | "args": [ 26 | "-ginkgo.failFast", 27 | ], 28 | "program": "${workspaceFolder}/test/e2e", 29 | }, 30 | { 31 | "name": "ginkgo conformance", 32 | "type": "go", 33 | "request": "launch", 34 | "mode": "test", 35 | "args": [ 36 | "-ginkgo.failFast", 37 | ], 38 | "program": "${workspaceFolder}/test/conformance", 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /catalog/alb.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: alb 5 | description: alauda loadbalancer controller 6 | annotations: 7 | # gitlab 仓库地址,格式:${group}/${name} 8 | gitlab.com/project-slug: container-platform/alb2 9 | gitlab.com/instance: gitlab-ce.alauda.cn 10 | 11 | # acp ci 流水线地址,格式:${project}/${cluster}/${ns}/${name} 12 | # 文档地址: https://dp.alauda.cn/docs/default/component/developer-platform/plugins/dp-cicd/#for-developer 13 | # 如果有多个流水线,用逗号分隔 14 | acp.cpaas.io/ci-pipeline: acp/business-build/acp-dev/alb 15 | 16 | # harbor 仓库信息,格式:${project}/${repo} 17 | # 如果有多个仓库,用逗号分隔 18 | goharbor.io/repository-slug: acp/alb2,acp/alb-nginx 19 | 20 | # sonarqube 项目信息(projectKey)。比如下面的 sonar 项目地址,projectKey 为 gitlab-ce.alauda.cn-developer-platform-octopus 21 | # https://build-sonar.alauda.cn/dashboard?id=gitlab-ce.alauda.cn-developer-platform-octopus 22 | sonarqube.org/project-key: gitlab-ce.alauda.cn-container-platform-alb2 23 | 24 | # 组件的管理人员,格式 ${owner} 25 | acp.cpaas.io/owner: congwu@alauda.io 26 | acp.cpaas.io/functional-attributes: core 27 | # 技术文档目录,相对于 catalog-info.yaml 文件 mkdocs.yaml 所在的位置。比如下面的目录结构,技术文档目录为 ./ 28 | # . 29 | # ├── mkdocs.mk 30 | # ├── catalog-info.yaml 31 | backstage.io/techdocs-ref: dir:./ 32 | spec: 33 | # 组件属于什么类型 34 | type: service 35 | # 组件属于什么生命周期,可选值{"experimental":"试验阶段","production":"维护阶段","deprecated":"周期末尾阶段,稍后回收"} 36 | lifecycle: production 37 | # 组件所属团队 38 | owner: ACP 39 | -------------------------------------------------------------------------------- /cmd/utils/albctl/cmd/debug.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | // case1. rule has no ep 12 | // case2. rule start with / 13 | 14 | var debug = &cobra.Command{ 15 | Use: "debug", 16 | Short: "auto debug", 17 | RunE: func(cmd *cobra.Command, args []string) error { 18 | ctx := cmd.Context() 19 | now := time.Now() 20 | defer func() { 21 | fmt.Printf("over spend %v\n", time.Since(now)) 22 | }() 23 | return autodebug(ctx) 24 | }, 25 | } 26 | 27 | func autodebug(ctx context.Context) error { 28 | return nil 29 | } 30 | 31 | func init() { 32 | rootCmd.AddCommand(debug) 33 | } 34 | -------------------------------------------------------------------------------- /cmd/utils/albctl/cmd/log_analyze_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestParse(t *testing.T) { 9 | lines := []string{ 10 | `[14/Oct/2024:07:11:12 +0000] 158.246.10.93 "158.246.0.58" "POST /mfs/channel/http.do HTTP/1.1" 200 504 200 "158.246.9.68:9080,158.246.9.160:9080" "Apache-HttpClient/4.5.7 (Java/1.8.0_322)" "158.219.208.229, 158.246.0.82" 5.035 5.000,0.035`, 11 | `[14/Oct/2024:07:11:12 +0000] 158.246.10.93 "158.246.0.58" "POST /mfs/channel/http.do HTTP/1.1" 200 504, 200 158.246.9.68:9080, 158.246.9.160:9080 "Apache-HttpClient/4.5.7 (Java/1.8.0_322)" "158.219.208.229, 158.246.0.82" 5.035 5.000, 0.035`, 12 | } 13 | for _, l := range lines { 14 | fmt.Printf("%+v", ParseItHarder(l)) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cmd/utils/albctl/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | type GlobalOpt struct { 11 | KubecfgPath string 12 | } 13 | 14 | var GOpt = GlobalOpt{} 15 | 16 | // rootCmd represents the base command when called without any subcommands 17 | var rootCmd = &cobra.Command{ 18 | Use: "albctl", 19 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 20 | if GOpt.KubecfgPath != "" { 21 | return nil 22 | } 23 | env := os.Getenv("KUBECONFIG") 24 | if env != "" { 25 | GOpt.KubecfgPath = env 26 | } 27 | defaultPath := os.Getenv("HOME") + "/.kube/config" 28 | _, err := os.Stat(defaultPath) 29 | if GOpt.KubecfgPath == "" && err == nil { 30 | GOpt.KubecfgPath = defaultPath 31 | } 32 | if GOpt.KubecfgPath == "" { 33 | return fmt.Errorf("need kubecfg path") 34 | } 35 | return nil 36 | }, 37 | Short: "debug util for alb", 38 | } 39 | 40 | func Execute() { 41 | if err := rootCmd.Execute(); err != nil { 42 | os.Exit(1) 43 | } 44 | } 45 | 46 | func init() { 47 | } 48 | -------------------------------------------------------------------------------- /cmd/utils/albctl/cmd/rule_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "testing" 7 | 8 | "alauda.io/alb2/config" 9 | "alauda.io/alb2/driver" 10 | . "alauda.io/alb2/pkg/utils/test_utils" 11 | lu "alauda.io/alb2/utils" 12 | "alauda.io/alb2/utils/log" 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestPolicyInReal(t *testing.T) { 17 | if os.Getenv("TestPolicyInReal") == "" { 18 | return 19 | } 20 | ctx := context.Background() 21 | mock := config.DefaultMock() 22 | l := log.L() 23 | kconf, err := driver.GetKubeCfgFromFile(os.Getenv("KUBECONFIG")) 24 | assert.NoError(t, err) 25 | drv, err := driver.NewDriver(driver.DrvOpt{Ctx: ctx, Cf: kconf, Opt: driver.Cfg2opt(mock)}) 26 | assert.NoError(t, err) 27 | policy, err := GetPolicy(PolicyGetCtx{Ctx: ctx, Name: "global-alb2", Ns: "cpaas-system", Drv: drv, L: l}) 28 | assert.NoError(t, err) 29 | _ = policy 30 | _ = lu.PrettyJson(policy) 31 | l.Info("p", "p", lu.PrettyJson(policy)) 32 | } 33 | -------------------------------------------------------------------------------- /cmd/utils/albctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "alauda.io/alb2/cmd/utils/albctl/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/utils/dirhash/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "alauda.io/alb2/utils/dirhash" 8 | ) 9 | 10 | func main() { 11 | out, err := dirhash.HashDir(os.Args[1], "", dirhash.DefaultHash) 12 | if err != nil { 13 | panic(err) 14 | } 15 | fmt.Printf("%s\n", out) 16 | } 17 | -------------------------------------------------------------------------------- /cmd/utils/ngx_gen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | 9 | . "alauda.io/alb2/pkg/controller/ngxconf" 10 | ) 11 | 12 | func main() { 13 | ngx_raw, err := io.ReadAll(os.Stdin) 14 | if err != nil { 15 | panic(err) 16 | } 17 | ngx, err := NgxTmplCfgFromYaml(string(ngx_raw)) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | out, err := RenderNginxConfigEmbed(*ngx) 23 | if err != nil { 24 | panic(err) 25 | } 26 | fmt.Print(strings.TrimSpace(out)) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/utils/sync_rbac/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // 1. alb cluster come from alb-clusterrole.json 5 | // 2. alb-operator clusterrole come from resource/rbac/alb-operator-clusterrole.yaml 6 | // this tools will update operator clusterrole in chart's operator-clusterrole.yaml and deploy-csv.yaml 7 | } 8 | -------------------------------------------------------------------------------- /cmd/utils/tweak_gen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path" 7 | 8 | "alauda.io/alb2/pkg/operator/controllers/depl/resources/configmap" 9 | ) 10 | 11 | // generate configmap used for nginx test 12 | func main() { 13 | outDir := os.Args[1] 14 | err := os.MkdirAll(outDir, 0o700) 15 | if err != nil { 16 | panic(err) 17 | } 18 | fmt.Printf("%v", configmap.HTTP) 19 | fmt.Printf("%v", outDir) 20 | toFile(configmap.HTTP, path.Join(outDir, "http.conf")) 21 | toFile(configmap.HTTPSERVER, path.Join(outDir, "http_server.conf")) 22 | toFile(configmap.UPSTREAM, path.Join(outDir, "upstream.conf")) 23 | toFile(configmap.STREAM_COMMON, path.Join(outDir, "stream-common.conf")) 24 | toFile(configmap.STREAM_TCP, path.Join(outDir, "stream-tcp.conf")) 25 | toFile(configmap.STREAM_UDP, path.Join(outDir, "stream-udp.conf")) 26 | toFile(configmap.GRPCSERVER, path.Join(outDir, "grpc_server.conf")) 27 | } 28 | 29 | func toFile(content string, path string) { 30 | f, err := os.Create(path) 31 | if err != nil { 32 | panic(err) 33 | } 34 | defer f.Close() 35 | _, err = f.WriteString(content) 36 | if err != nil { 37 | panic(err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /config/config_ext.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "sigs.k8s.io/controller-runtime/pkg/client" 4 | 5 | func GetAlbKey(c *Config) client.ObjectKey { 6 | return client.ObjectKey{ 7 | Namespace: c.GetNs(), 8 | Name: c.GetAlbName(), 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /config/mock_config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "time" 5 | 6 | . "alauda.io/alb2/pkg/config" 7 | ) 8 | 9 | // type MockConfig ALBRunConfig 10 | 11 | func Mock(name, ns string) *Config { 12 | mock := DefaultMock() 13 | mock.ALBRunConfig.Name = name 14 | mock.ALBRunConfig.Ns = ns 15 | return mock 16 | } 17 | 18 | func DefaultMock() *Config { 19 | return &Config{ 20 | ALBRunConfig: ALBRunConfig{ 21 | Name: "alb-dev", 22 | Ns: "cpaas-system", 23 | Domain: "cpaas.io", 24 | Controller: ControllerConfig{ 25 | HttpPort: 80, 26 | HttpsPort: 443, 27 | NetworkMode: "host", 28 | MetricsPort: 1936, 29 | BackLog: 100, 30 | Flags: ControllerFlags{ 31 | EnableIPV6: true, 32 | }, 33 | }, 34 | Gateway: GatewayConfig{}, 35 | }, 36 | ExtraConfig: ExtraConfig{ 37 | Leader: LeaderConfig{ 38 | LeaseDuration: time.Second * time.Duration(120), 39 | RenewDeadline: time.Second * time.Duration(40), 40 | RetryPeriod: time.Second * time.Duration(12), 41 | SkipExit: true, 42 | }, 43 | }, 44 | Names: NewNames("cpaas.io"), 45 | } 46 | } 47 | 48 | func UseMock(cfg *Config) { 49 | if cfg == nil { 50 | cfg = DefaultMock() 51 | } 52 | InTestSetConfig(*cfg) 53 | } 54 | -------------------------------------------------------------------------------- /config/types.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Mode string 4 | 5 | var ModeKey = "MODE" 6 | 7 | const ( 8 | Controller Mode = "controller" 9 | Operator Mode = "operator" 10 | ) 11 | 12 | type ControllerNetWorkMode string 13 | 14 | var NetworkModeKey = "NETWORK_MODE" 15 | 16 | const ( 17 | Host ControllerNetWorkMode = "host" 18 | Container ControllerNetWorkMode = "container" 19 | ) 20 | 21 | type NginxCfg struct { 22 | NginxTemplatePath string 23 | NewConfigPath string 24 | OldConfigPath string 25 | NewPolicyPath string 26 | EnablePrometheus bool 27 | EnableHttp2 bool 28 | EnableGzip bool 29 | BackLog int 30 | EnableIpv6 bool 31 | TweakDir string 32 | } 33 | -------------------------------------------------------------------------------- /controller/cli/cert_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "sigs.k8s.io/controller-runtime/pkg/client" 8 | ) 9 | 10 | func TestCert(t *testing.T) { 11 | assert.Equal(t, 12 | formatCertsMap(map[string]map[string][]client.ObjectKey{ 13 | "80": { 14 | "a.com": { 15 | {Namespace: "a", Name: "a2"}, 16 | {Namespace: "a", Name: "a1"}, 17 | {Namespace: "a", Name: "a3"}, 18 | }, 19 | }, 20 | "90": { 21 | "b.com": { 22 | {Namespace: "a", Name: "b1"}, 23 | }, 24 | "c.com": { 25 | {Namespace: "a", Name: "c1"}, 26 | }, 27 | }, 28 | "91": { 29 | "b.com": { 30 | {Namespace: "a", Name: "b2"}, 31 | }, 32 | }, 33 | }), 34 | map[string]client.ObjectKey{ 35 | "a.com": {Namespace: "a", Name: "a1"}, 36 | "b.com/90": {Namespace: "a", Name: "b1"}, 37 | "b.com/91": {Namespace: "a", Name: "b2"}, 38 | "c.com": {Namespace: "a", Name: "c1"}, 39 | }, 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /controller/cli/policy_l4.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | . "alauda.io/alb2/controller/types" 5 | albv1 "alauda.io/alb2/pkg/apis/alauda/v1" 6 | ) 7 | 8 | func (p *PolicyCli) initStreamModeFt(ft *Frontend, ngxPolicy *NgxPolicy) { 9 | // create a default rule for stream mode ft. 10 | policy := Policy{} 11 | policy.Source = Source{} 12 | policy.Subsystem = SubsystemStream 13 | // @ft_default_policy 14 | upstream, rule := getName(ft) 15 | policy.Upstream = upstream 16 | policy.Rule = rule 17 | p.cus.InitL4DefaultPolicy(ft, &policy) 18 | 19 | if ft.Protocol == albv1.FtProtocolTCP { 20 | ngxPolicy.Stream.Tcp[ft.Port] = append(ngxPolicy.Stream.Tcp[ft.Port], &policy) 21 | } 22 | if ft.Protocol == albv1.FtProtocolUDP { 23 | ngxPolicy.Stream.Udp[ft.Port] = append(ngxPolicy.Stream.Udp[ft.Port], &policy) 24 | } 25 | } 26 | 27 | // gateway-api中就是ft没有默认backend-group 但是有rule 28 | func getName(ft *Frontend) (upstream string, rule string) { 29 | if len(ft.Rules) > 0 { 30 | rule := ft.Rules[0] 31 | if rule.BackendGroup != nil { 32 | return rule.BackendGroup.Name, rule.RuleID 33 | } 34 | // 可能是redirect规则。用rule id即可。在没有backend-group的情况下,upstream name 是什么都行 35 | return rule.RuleID, rule.RuleID 36 | } 37 | if ft.BackendGroup != nil { 38 | return ft.BackendGroup.Name, ft.BackendGroup.Name 39 | } 40 | return "", "" 41 | } 42 | -------------------------------------------------------------------------------- /controller/modules/consts.go: -------------------------------------------------------------------------------- 1 | package modules 2 | 3 | import alb2v1 "alauda.io/alb2/pkg/apis/alauda/v1" 4 | 5 | const ( 6 | // ProtoHTTP is the protocol of http frontend 7 | ProtoHTTP = alb2v1.FtProtocolHTTP 8 | ProtoHTTPS = alb2v1.FtProtocolHTTPS 9 | ) 10 | 11 | // source type 12 | const ( 13 | TypeIngress = "ingress" 14 | TypeFtDefaultRouter = "ft_default_router" 15 | TypeExtension = "extension" 16 | TypeHttpRoute = "httpRoute" 17 | TypeTCPRoute = "tcpRoute" 18 | TypeUDPRoute = "udpRoute" 19 | ) 20 | 21 | const ( 22 | ProjectALL = "ALL_ALL" 23 | ) 24 | 25 | type AlbPhase string 26 | 27 | const ( 28 | PhaseStarting AlbPhase = "starting" 29 | PhaseRunning AlbPhase = "running" 30 | PhaseTerminating AlbPhase = "terminating" 31 | ) 32 | -------------------------------------------------------------------------------- /controller/state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "sync" 5 | 6 | . "alauda.io/alb2/controller/modules" 7 | ) 8 | 9 | // 维护一些全局的alb的状态 目前只有优雅退出的特性用到了 10 | 11 | type State struct { 12 | phase AlbPhase 13 | lock sync.Mutex 14 | } 15 | 16 | var ( 17 | instance *State 18 | once sync.Once 19 | ) 20 | 21 | func GetState() *State { 22 | once.Do(func() { 23 | instance = &State{ 24 | phase: PhaseStarting, 25 | lock: sync.Mutex{}, 26 | } 27 | }) 28 | return instance 29 | } 30 | 31 | func (s *State) GetPhase() AlbPhase { 32 | s.lock.Lock() 33 | defer s.lock.Unlock() 34 | return s.phase 35 | } 36 | 37 | func (s *State) SetPhase(p AlbPhase) { 38 | s.lock.Lock() 39 | defer s.lock.Unlock() 40 | s.phase = p 41 | } 42 | -------------------------------------------------------------------------------- /controller/types/consts.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | SubsystemHTTP = "http" 5 | SubsystemStream = "stream" 6 | 7 | PolicySIPHash = "sip-hash" 8 | PolicyCookie = "cookie" 9 | 10 | CaCert = "ca.crt" 11 | ) 12 | 13 | var ( 14 | LastConfig = "" 15 | LastFailure = false 16 | ) 17 | 18 | const ( 19 | ModeTCP = "tcp" 20 | ModeHTTP = "http" 21 | ModeUDP = "udp" 22 | ModegRPC = "grpc" 23 | ) 24 | 25 | const ( 26 | RuleTypeIngress = "ingress" 27 | RuleTypeGateway = "gateway" 28 | ) 29 | -------------------------------------------------------------------------------- /controller/types/policyext_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | "testing" 7 | 8 | otelt "alauda.io/alb2/pkg/controller/ext/otel/types" 9 | lu "alauda.io/alb2/utils" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestJson(t *testing.T) { 14 | p := Policy{} 15 | p_json := lu.PrettyJson(p) 16 | t.Log() 17 | assert.Equal(t, !strings.Contains(p_json, "null"), true) 18 | } 19 | 20 | func TestToMaps(t *testing.T) { 21 | p := PolicyExtCfg{ 22 | PolicyExt: PolicyExt{ 23 | Otel: &otelt.OtelConf{ 24 | Exporter: &otelt.Exporter{}, 25 | }, 26 | RewriteResponse: &RewriteResponseConfig{}, 27 | }, 28 | } 29 | m := p.ToMaps() 30 | js, err := json.MarshalIndent(m, " ", " ") 31 | assert.NoError(t, err) 32 | t.Logf("m %s", string(js)) 33 | assert.Equal(t, 2, len(m)) 34 | } 35 | 36 | func TestClean(t *testing.T) { 37 | p := PolicyExt{ 38 | Otel: &otelt.OtelConf{ 39 | Exporter: &otelt.Exporter{}, 40 | }, 41 | RewriteResponse: &RewriteResponseConfig{}, 42 | } 43 | p.Clean("otel") 44 | } 45 | -------------------------------------------------------------------------------- /deploy/README.md: -------------------------------------------------------------------------------- 1 | ## csv and rbac 2 | 现在csv是直接在chart中部署的 3 | 因为发现这种方式无法创建出serviceaccount,所以rbac相关的资源是chart直接创建的 4 | ## gatewayapi 5 | | gatewayapi v0.6.2 | v1alpha2 | v1beta1 | v1 | 6 | |-------------------|------------|------------|----| 7 | | gatewayclass | v | v(storage) | | 8 | | gateway | v | v(storage) | | 9 | | httproute | v | v(storage) | | 10 | | tcproute | v(storage) | | | 11 | | udproute | v(storage) | | | 12 | | tlsroute | v(storage) | | | 13 | | referencegrant | v(storage) | v | 14 | | grpcroute | v(storage) | | | 15 | |-------------------|------------|------------|----| 16 | 17 | | gatewayapi v1.0.0 | v1alpha2 | v1beta1 | v1 | 18 | |-------------------|------------|------------|----| 19 | | gatewayclass | | v(storage) | v | 20 | | gatway | | v(storage) | v | 21 | | httproute | | v(storage) | v | 22 | | tcproute | v(storage) | | | 23 | | udproute | v(storage) | | | 24 | | tlsroute | v(storage) | | | 25 | | referencegrant | v | v(storage) | | 26 | | grpcroute | v(storage) | | | 27 | | btlspolicy | v(storage) | | | -------------------------------------------------------------------------------- /deploy/chart/alb/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: alauda-alb2 2 | version: v3.19.0-beta.22.gad8523c5 3 | description: alauda loadbalancer version 2 4 | apiVersion: v2 5 | annotations: 6 | release: alpha 7 | branch: master 8 | commit: ad8523c5953f8a579f1cbc17774ef70fb399183a 9 | -------------------------------------------------------------------------------- /deploy/chart/alb/templates/alb.featuregate.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Capabilities.APIVersions.Has "ait.alauda.io/v1alpha2" -}} 2 | {{ $publicCloudProvider := .Values.global.publicCloudProvider }} 3 | {{ $clusterType := .Values.global.cluster.type }} 4 | {{ if has $clusterType $publicCloudProvider }} 5 | apiVersion: alauda.io/v1 6 | kind: ClusterAlaudaFeatureGate 7 | metadata: 8 | name: alb2 9 | namespace: '{{.Values.global.namespace}}' 10 | spec: 11 | description: "增强型负载均衡,为应用提供丰富功能的负载均衡策略和配置,集群级功能开关添加于 v3.12" 12 | enabled: true 13 | stage: GA 14 | {{ end }} 15 | {{- end }} -------------------------------------------------------------------------------- /deploy/chart/alb/templates/alb.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.defaultAlb }} 2 | {{- $global := .Values.global }} 3 | {{- $value_copy := deepCopy .Values }} 4 | {{- $value_without_global := unset $value_copy "global" }} 5 | {{- $value_without_console := unset $value_without_global "alaudaConsole" }} 6 | {{- $value_clean := $value_without_console }} 7 | {{- $cfg := $value_clean }} 8 | {{ $fullProjects := .Values.projects | uniq }} 9 | apiVersion: crd.alauda.io/v2beta1 10 | kind: ALB2 11 | metadata: 12 | name: {{ .Values.loadbalancerName }} 13 | namespace: {{ $global.namespace }} 14 | labels: 15 | alb.{{ $global.labelBaseDomain}}/managed-by: alb-operator 16 | alb.{{ $global.labelBaseDomain}}/migrate-from: sentry 17 | alb.{{ $global.labelBaseDomain}}/deploy-by: sentry 18 | alb.{{ $global.labelBaseDomain}}/default-alb: "true" 19 | {{- range $fullProjects }} 20 | {{ if . }} 21 | project.{{ $global.labelBaseDomain }}/{{ . }}: "true" 22 | {{ end}} 23 | {{- end}} 24 | annotations: 25 | {{ $global.labelBaseDomain }}/display-name: {{ .Values.displayName |quote }} 26 | helm.sh/waitResources: "[{\"apiVersion\": \"apps/v1\", \"kind\": \"Deployment\", \"namespace\": \"{{ .Release.Namespace }}\", \"name\": \"{{ .Values.loadbalancerName }}\"}]" 27 | alb.{{ $global.labelBaseDomain }}/migrate-backup: | 28 | {{ $cfg | toJson }} 29 | update-mode: put 30 | spec: 31 | address: {{ .Values.address | quote }} 32 | type: "nginx" 33 | config: 34 | {{ $cfg | toYaml | indent 4 }} 35 | {{- end }} -------------------------------------------------------------------------------- /deploy/chart/alb/templates/loadbalancer-service.featuregate.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Capabilities.APIVersions.Has "ait.alauda.io/v1alpha2" -}} 2 | apiVersion: alauda.io/v1 3 | kind: ClusterAlaudaFeatureGate 4 | metadata: 5 | name: loadbalancer-service 6 | namespace: '{{.Values.global.namespace}}' 7 | spec: 8 | description: "LoadBalancer类型Service,添加于v3.10" 9 | enabled: true 10 | stage: GA 11 | {{- end }} 12 | -------------------------------------------------------------------------------- /deploy/chart/alb/templates/operator-clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: alb-operator 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: alb-operator 9 | subjects: 10 | - kind: ServiceAccount 11 | name: alb-operator 12 | namespace: {{.Values.global.namespace}} -------------------------------------------------------------------------------- /deploy/chart/alb/templates/operator-sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | imagePullSecrets: 4 | {{- range $_, $v := .Values.global.registry.imagePullSecrets }} 5 | - name: {{ $v }} 6 | {{- end }} 7 | metadata: 8 | name: alb-operator 9 | namespace: {{.Values.global.namespace}} 10 | -------------------------------------------------------------------------------- /deploy/chart/alb/values.yaml: -------------------------------------------------------------------------------- 1 | ## global 2 | operator: 3 | albImagePullPolicy: Always 4 | defaultAlb: true # 部署默认的alb 5 | operatorReplicas: 1 6 | operatorDeployMode: "deployment" 7 | displayName: "" 8 | address: 127.0.0.1 # address of the default alb 9 | projects: [] 10 | global: 11 | platformscenario: base 12 | labelBaseDomain: cpaas.io 13 | namespace: cpaas-system 14 | registry: 15 | address: registry.alauda.cn:60080 16 | images: 17 | alb2: 18 | code: gitlab-ce.alauda.cn/container-platform/alb2 19 | support_arm: true 20 | repository: acp/alb2 21 | tag: v3.19.0-beta.22.gad8523c5 22 | nginx: 23 | code: gitlab-ce.alauda.cn/container-platform/alb2 24 | support_arm: true 25 | repository: acp/alb-nginx 26 | tag: "v3.19.0-beta.22.gad8523c5" 27 | resources: 28 | alb: 29 | limits: 30 | cpu: "200m" 31 | memory: 2Gi 32 | requests: 33 | cpu: 50m 34 | memory: 128Mi 35 | limits: 36 | cpu: "2" 37 | memory: 2Gi 38 | requests: 39 | cpu: 50m 40 | memory: 128Mi 41 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [[release-note/README|release-note]] 2 | ## features 3 | [[rules]] 4 | [[api-containermode-gateway-deploy]] 5 | [[api-ingressclass]] 6 | [[rules]] 7 | [[errorpage]] 8 | [[feature/otel/otel]] 9 | [[modsecurity.en]] 10 | [[auth]] -------------------------------------------------------------------------------- /docs/_res/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/docs/_res/architecture.png -------------------------------------------------------------------------------- /docs/feature/auth/dev_readme.md: -------------------------------------------------------------------------------- 1 | # ALB Auth 实现说明 2 | 3 | ALB 在实现 auth 相关 annotation 时采用了不同于 ingress-nginx 的实现方式: 4 | 5 | - ingress-nginx 是基于模板修改 nginx.conf 实现 6 | - ALB 是基于 OpenResty 的 Lua 实现 7 | 8 | 这种实现方式带来以下优势: 9 | 1. 支持更复杂的认证功能 10 | 2. 认证配置变更时无需重载 nginx 11 | 12 | 虽然实现方式不同,但 ALB 会保持与 ingress-nginx 的行为一致性: 13 | - 相同的 annotation 在 ingress-nginx 和 ALB 上效果一致,无需改动. 14 | 15 | 为了保证行为一致性,我们使用 ./test/conformance/ingress-nginx 中的测试用例来验证。这套测试用例可以同时在 ingress-nginx 和 ALB 上运行,确保功能的一致性。 16 | 17 | # 代码 18 | go 部分代码在 ./pkg/controller/ext/auth/auth.go 19 | lua 部分代码在 ./template/nginx/lua/plugins/auth/auth.lua -------------------------------------------------------------------------------- /docs/feature/errorpage/errorpage.md: -------------------------------------------------------------------------------- 1 | ## Error Page 2 | ### 概述 3 | 我们不希望用户能看到openresty这种体现技术栈的字样。 4 | 1. 当应用返回错误时, alb返回的body和应用返回的body一致。 5 | 1. 没有body时,alb也不会返回body 6 | 2. 当alb自身返回错误时, alb返回的body为 7 | ``` 8 | X-Error: $status 9 | ``` 10 | ### 例外 11 | 当开启了 [[modsecurity]] 之后,如果因为waf规则返回了错误码,返回的body为 12 | ``` 13 | 14 | 15 | 403 Forbidden 16 | 17 | 18 |
19 |

403 Forbidden

20 |
21 |
22 |
openresty
23 | 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/feature/otel/_res/jaeger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/docs/feature/otel/_res/jaeger.png -------------------------------------------------------------------------------- /docs/feature/otel/_res/trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/docs/feature/otel/_res/trace.png -------------------------------------------------------------------------------- /docs/release-note/README.md: -------------------------------------------------------------------------------- 1 | # ACP v3.18 2 | ## ACP v3.18.1 3 | state: RELEASE 4 | chart: v3.18.2 5 | image: v3.18.2 6 | ### change 7 | #### feature 8 | * add support of [[otel]] [otel](https://github.com/alauda/alb/commit/16ee00dd009cda1bd5fb48ad803b48fe5427d2b6) 9 | * add cpaas.io/project label in ingress synced rule. 10 | * add support of [[modsecurity]] 11 | #### other 12 | * tweak github ci. we could build and test in github now 13 | * deploy alb-operator via deployment. do not use csv anymore 14 | * add MonitorDashboard in chart 15 | * https and authed metrics 16 | * add source name/ns label in rule. (first 63 chars if name/ns is longer than 63) 17 | * api: filter project when list rules 18 | * unquote cookie value when rewrite request header via var 19 | * swap policy 20 | * fix CORS when has multi-domain 21 | * donot use placeholder crt/key -------------------------------------------------------------------------------- /driver/constants.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | const ( 4 | OwnerUnknown = "Unknown" 5 | ) 6 | -------------------------------------------------------------------------------- /gateway/constant.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | sets "github.com/deckarep/golang-set/v2" 5 | ) 6 | 7 | // log tag 8 | const ( 9 | ALB_GATEWAY_CONTROLLER = "agctl" // gateway/xxroute controller relevant. a(lb)g(ateway)c(on)t(rol)l(er) 10 | ALB_GATEWAY_NGINX = "agng" // nginx config relevant. a(lb)g(ateway)ng(inxconfiggenerater) 11 | ) 12 | 13 | const ( 14 | GATEWAY_GROUP = "gateway.networking.k8s.io" 15 | GATEWAY_KIND = "Gateway" 16 | ) 17 | 18 | const ( 19 | GatewayClassKind = "GatewayClass" 20 | GatewayKind = "Gateway" 21 | HttpRouteKind = "HTTPRoute" 22 | TcpRouteKind = "TCPRoute" 23 | UdpRouteKind = "UDPRoute" 24 | ) 25 | 26 | var SUPPORT_KIND_MAP map[string][]string = map[string][]string{ 27 | "TCP": {TcpRouteKind}, 28 | "UDP": {UdpRouteKind}, 29 | "HTTP": {HttpRouteKind}, 30 | "HTTPS": {HttpRouteKind}, 31 | } 32 | 33 | var SUPPORT_KIND_SET sets.Set[string] = sets.NewSet(TcpRouteKind, UdpRouteKind, HttpRouteKind) 34 | -------------------------------------------------------------------------------- /gateway/ctl/constants.go: -------------------------------------------------------------------------------- 1 | package ctl 2 | 3 | type CommonRouteConditionReason string 4 | 5 | const ( 6 | CommonRouteReasonInvalidSectionName CommonRouteConditionReason = "InvalidSectionName" 7 | CommonRouteReasonUnAllowRoute CommonRouteConditionReason = "UnAllowRoute" 8 | CommonRouteReasonInvalidKind CommonRouteConditionReason = "InvalidKind" 9 | ) 10 | -------------------------------------------------------------------------------- /gateway/ctl/hostname_filter.go: -------------------------------------------------------------------------------- 1 | package ctl 2 | 3 | import ( 4 | . "alauda.io/alb2/gateway" 5 | . "alauda.io/alb2/gateway/utils" 6 | "github.com/go-logr/logr" 7 | "github.com/samber/lo" 8 | gv1 "sigs.k8s.io/gateway-api/apis/v1" 9 | ) 10 | 11 | type HostNameFilter struct { 12 | log logr.Logger 13 | } 14 | 15 | func (c *HostNameFilter) Name() string { 16 | return "HostNameFilter" 17 | } 18 | 19 | func (c *HostNameFilter) FilteRoute(ref gv1.ParentReference, r *Route, ls *Listener) bool { 20 | // allow routes 21 | lsHost := ls.Hostname 22 | if lsHost == nil { 23 | return true 24 | } 25 | 26 | h, ok := r.route.(*HTTPRoute) 27 | // only focus on http route. 28 | if !ok { 29 | return true 30 | } 31 | 32 | routeHost := lo.Map(h.Spec.Hostnames, func(s gv1.Hostname, _ int) string { return string(s) }) 33 | 34 | domains := FindIntersection(string(*lsHost), routeHost) 35 | if len(domains) == 0 { 36 | r.unAllowRoute(ref, "no intersection hostname") 37 | return false 38 | } 39 | return true 40 | } 41 | -------------------------------------------------------------------------------- /gateway/ctl/hostname_filter_test.go: -------------------------------------------------------------------------------- 1 | package ctl 2 | 3 | import ( 4 | "testing" 5 | 6 | "alauda.io/alb2/gateway/utils" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestHostNameFilter(t *testing.T) { 11 | type TestCase struct { 12 | host string 13 | route []string 14 | result []string 15 | } 16 | cases := []TestCase{ 17 | { 18 | host: "a.com", 19 | route: []string{"a.com"}, 20 | result: []string{"a.com"}, 21 | }, 22 | { 23 | host: "a.com", 24 | route: []string{}, 25 | result: []string{"a.com"}, 26 | }, 27 | { 28 | host: "*.a.com", 29 | route: []string{"a.com"}, 30 | result: []string{}, 31 | }, 32 | { 33 | host: "*.a.com", 34 | route: []string{}, 35 | result: []string{"*.a.com"}, 36 | }, 37 | { 38 | host: "*.a.com", 39 | route: []string{"a.a.com", "b.a.com"}, 40 | result: []string{"a.a.com", "b.a.com"}, 41 | }, 42 | { 43 | host: "b.a.com", 44 | route: []string{"*.a.com", "b.a.com", "a.a.com"}, 45 | result: []string{"*.a.com", "b.a.com"}, 46 | }, 47 | } 48 | for _, test := range cases { 49 | result := utils.FindIntersection(test.host, test.route) 50 | assert.Equal(t, test.result, result) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /gateway/ctl/reservedPortFilter.go: -------------------------------------------------------------------------------- 1 | package ctl 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-logr/logr" 7 | gv1b1t "sigs.k8s.io/gateway-api/apis/v1" 8 | ) 9 | 10 | const RouteNotReadyReasonReservedPort = "ReservedPortUsed" 11 | 12 | type ReservedPortFilter struct { 13 | log logr.Logger 14 | reservedPorts map[int]bool 15 | } 16 | 17 | func NewReservedPortFilter(log logr.Logger, ports []int) ReservedPortFilter { 18 | m := map[int]bool{} 19 | for _, p := range ports { 20 | m[p] = true 21 | } 22 | log.Info("reservedPorts", "ports", m) 23 | return ReservedPortFilter{ 24 | log: log, 25 | reservedPorts: m, 26 | } 27 | } 28 | 29 | func (c *ReservedPortFilter) Name() string { 30 | return "ReservedPortFilter" 31 | } 32 | 33 | func (c *ReservedPortFilter) FilteRoute(ref gv1b1t.ParentReference, r *Route, ls *Listener) bool { 34 | if c.reservedPorts[int(ls.Port)] { 35 | r.unAllowRouteWithReason(ref, fmt.Sprintf("%v is our reserved port", c.reservedPorts), RouteNotReadyReasonReservedPort) 36 | return false 37 | } 38 | return true 39 | } 40 | -------------------------------------------------------------------------------- /gateway/nginx/policyattachment/manager.go: -------------------------------------------------------------------------------- 1 | package policyattachment 2 | 3 | import ( 4 | "context" 5 | 6 | . "alauda.io/alb2/controller/types" 7 | "alauda.io/alb2/driver" 8 | . "alauda.io/alb2/gateway/nginx/policyattachment/types" 9 | "github.com/go-logr/logr" 10 | ) 11 | 12 | type PolicyAttachmentManager struct { 13 | ctx context.Context 14 | log logr.Logger 15 | drv *driver.KubernetesDriver 16 | timeout TimeoutPolicy 17 | } 18 | 19 | // manager of all policyattachment, recreate when re-render config. 20 | func NewPolicyAttachmentManager(ctx context.Context, drv *driver.KubernetesDriver, log logr.Logger) (*PolicyAttachmentManager, error) { 21 | timeout, err := NewTimeoutPolicy(ctx, log.WithName("timeout"), drv) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return &PolicyAttachmentManager{ 26 | ctx: ctx, 27 | log: log, 28 | drv: drv, 29 | timeout: *timeout, 30 | }, nil 31 | } 32 | 33 | func (pm *PolicyAttachmentManager) OnRule(ft *Frontend, rule *InternalRule, ref Ref) error { 34 | // TODO 当一个policyattachment出错时,应该如何处理? 35 | err := pm.timeout.OnRule(ft, rule, ref) 36 | if err != nil { 37 | return err 38 | } 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /gateway/nginx/policyattachment/timeout_policy_test.go: -------------------------------------------------------------------------------- 1 | package policyattachment 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | gatewayPolicy "alauda.io/alb2/pkg/apis/alauda/gateway/v1alpha1" 8 | "github.com/openlyinc/pointy" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestIPolicyAttachmentConfig(t *testing.T) { 13 | timeout := gatewayPolicy.TimeoutPolicyConfig{ 14 | ProxyConnectTimeoutMs: nil, 15 | ProxyReadTimeoutMs: pointy.Uint(10), 16 | } 17 | timeoutJson, err := json.Marshal(timeout) 18 | assert.Equal(t, string(timeoutJson), `{"proxy_read_timeout_ms":10}`) 19 | assert.NoError(t, err) 20 | t.Logf("%s", timeoutJson) 21 | timeout1 := TimeoutPolicyConfig(timeout) 22 | ret := TimeoutPolicyConfig{} 23 | ret.FromConfig(timeout1.IntoConfig()) 24 | assert.Nil(t, ret.ProxyConnectTimeoutMs) 25 | assert.Equal(t, *ret.ProxyReadTimeoutMs, uint(10)) 26 | assert.Nil(t, ret.ProxySendTimeoutMs) 27 | } 28 | -------------------------------------------------------------------------------- /gateway/nginx/types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | pmType "alauda.io/alb2/gateway/nginx/policyattachment/types" 8 | albv1 "alauda.io/alb2/pkg/apis/alauda/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | gatewayType "sigs.k8s.io/gateway-api/apis/v1" 11 | 12 | "alauda.io/alb2/controller/types" 13 | "alauda.io/alb2/gateway" 14 | ) 15 | 16 | type Listener struct { 17 | gatewayType.Listener 18 | Gateway client.ObjectKey 19 | Generation int64 20 | CreateTime time.Time 21 | Routes []gateway.CommonRoute 22 | } 23 | 24 | type FtMap map[string]*types.Frontend 25 | 26 | func (f FtMap) SetFt(protocol string, port albv1.PortNumber, ft *types.Frontend) { 27 | key := fmt.Sprintf("%v:%v", protocol, port) 28 | f[key] = ft 29 | } 30 | 31 | type GatewayAlbTranslate interface { 32 | TransLate(ls []*Listener, ftMap FtMap) error 33 | } 34 | 35 | // who implement this interface have responsibility to call OnRule when a rule been create. 36 | type GatewayAlbPolicyAttachment interface { 37 | SetPolicyAttachmentHandle(handle pmType.PolicyAttachmentHandle) 38 | } 39 | -------------------------------------------------------------------------------- /gateway/nginx/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | 6 | "alauda.io/alb2/utils" 7 | gatewayType "sigs.k8s.io/gateway-api/apis/v1" 8 | 9 | . "alauda.io/alb2/controller/types" 10 | ) 11 | 12 | // translate gateway matchType.to alb op 13 | // Exact => EQ 14 | // PathPrefix => STARTS_WITH 15 | // RegularExpression => REGEX 16 | // nil => EQ 17 | // otherwise return err 18 | func ToOP(matchType *string) (string, error) { 19 | if matchType == nil { 20 | return utils.OP_EQ, nil 21 | } 22 | switch *matchType { 23 | case "Exact": 24 | return utils.OP_EQ, nil 25 | case "PathPrefix": 26 | return utils.OP_STARTS_WITH, nil 27 | case "RegularExpression": 28 | return utils.OP_REGEX, nil 29 | default: 30 | return "", fmt.Errorf("unsupported match type %v", matchType) 31 | } 32 | } 33 | 34 | func BackendRefsToService(refs []gatewayType.BackendRef) ([]*BackendService, error) { 35 | svcs := []*BackendService{} 36 | for _, ref := range refs { 37 | kind := ref.Kind 38 | if kind != nil && *kind != "Service" { 39 | return nil, fmt.Errorf("gateway: backend ref kind is not service but %v", kind) 40 | } 41 | if ref.Namespace == nil || ref.Port == nil || ref.Weight == nil { 42 | return nil, fmt.Errorf("invalid ref %v", ref) 43 | } 44 | svcs = append(svcs, &BackendService{ 45 | ServiceNs: string(*ref.Namespace), 46 | ServiceName: string(ref.Name), 47 | ServicePort: int(*ref.Port), 48 | Weight: int(*ref.Weight), 49 | }) 50 | } 51 | return svcs, nil 52 | } 53 | -------------------------------------------------------------------------------- /gateway/utils/hostname.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strings" 4 | 5 | func FindIntersection(lsHost string, routeHost []string) []string { 6 | if len(routeHost) == 0 { 7 | return []string{lsHost} 8 | } 9 | ret := []string{} 10 | 11 | for _, rh := range routeHost { 12 | if matchDomain(lsHost, rh) { 13 | ret = append(ret, rh) 14 | } 15 | } 16 | return ret 17 | } 18 | 19 | func matchDomain(host, route string) bool { 20 | hostIsWildcard := strings.HasPrefix(host, "*.") 21 | routeIsWildcard := strings.HasPrefix(route, "*.") 22 | if hostIsWildcard && !routeIsWildcard { 23 | hostWithoutWildcard := strings.TrimPrefix(host, "*") 24 | return strings.HasSuffix(route, hostWithoutWildcard) 25 | } 26 | if !hostIsWildcard && routeIsWildcard { 27 | routeWithoutWildcard := strings.TrimPrefix(route, "*") 28 | return strings.HasSuffix(host, routeWithoutWildcard) 29 | } 30 | return host == route 31 | } 32 | -------------------------------------------------------------------------------- /ingress/project.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "fmt" 5 | 6 | m "alauda.io/alb2/controller/modules" 7 | "github.com/thoas/go-funk" 8 | networkingv1 "k8s.io/api/networking/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/labels" 11 | ) 12 | 13 | func (c *Controller) GetProjectIngresses(projects []string) []*networkingv1.Ingress { 14 | if funk.ContainsString(projects, m.ProjectALL) { 15 | ingress, err := c.ingressLister.Ingresses("").List(labels.Everything()) 16 | if err != nil { 17 | c.log.Error(err, "") 18 | return nil 19 | } 20 | return ingress 21 | } 22 | var allIngresses []*networkingv1.Ingress 23 | for _, project := range projects { 24 | sel := labels.Set{fmt.Sprintf("%s/project", c.GetDomain()): project}.AsSelector() 25 | nss, err := c.kd.Client.CoreV1().Namespaces().List(c.kd.Ctx, metav1.ListOptions{LabelSelector: sel.String()}) 26 | if err != nil { 27 | c.log.Error(err, "") 28 | return nil 29 | } 30 | for _, ns := range nss.Items { 31 | ingress, err := c.ingressLister.Ingresses(ns.Name).List(labels.Everything()) 32 | if err != nil { 33 | c.log.Error(err, "") 34 | return nil 35 | } 36 | allIngresses = append(allIngresses, ingress...) 37 | } 38 | } 39 | return allIngresses 40 | } 41 | -------------------------------------------------------------------------------- /ingress/resync_test.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "k8s.io/apimachinery/pkg/util/wait" 9 | ) 10 | 11 | func TestWait(t *testing.T) { 12 | ctx, cancel := context.WithCancel(context.Background()) 13 | // we should wait a interval 14 | t.Logf("start %v", time.Now()) 15 | go wait.UntilWithContext(ctx, func(ctx context.Context) { 16 | t.Logf("in %v", time.Now()) 17 | }, time.Millisecond*100) 18 | time.Sleep(time.Second * 1) 19 | cancel() 20 | t.Logf("end %v", time.Now()) 21 | time.Sleep(time.Millisecond * 500) 22 | } 23 | -------------------------------------------------------------------------------- /ingress/util.go: -------------------------------------------------------------------------------- 1 | package ingress 2 | 3 | import ( 4 | "fmt" 5 | 6 | "k8s.io/apimachinery/pkg/util/intstr" 7 | "sigs.k8s.io/controller-runtime/pkg/client" 8 | 9 | networkingv1 "k8s.io/api/networking/v1" 10 | ) 11 | 12 | func HasDefaultBackend(ing *networkingv1.Ingress) bool { 13 | return len(ing.Spec.Rules) == 0 && 14 | ing.Spec.DefaultBackend != nil && 15 | ing.Spec.DefaultBackend.Resource == nil && 16 | ing.Spec.DefaultBackend.Service != nil 17 | } 18 | 19 | func ToInStr(backendPort networkingv1.ServiceBackendPort) intstr.IntOrString { 20 | intStrType := intstr.Int 21 | if backendPort.Number == 0 { 22 | intStrType = intstr.String 23 | } 24 | return intstr.IntOrString{Type: intStrType, IntVal: backendPort.Number, StrVal: backendPort.Name} 25 | } 26 | 27 | type NotExistsError string 28 | 29 | // Error implements the error interface. 30 | func (e NotExistsError) Error() string { 31 | return fmt.Sprintf("no object matching key %q in local store", string(e)) 32 | } 33 | 34 | func IngKey(ing *networkingv1.Ingress) client.ObjectKey { 35 | return client.ObjectKey{ 36 | Namespace: ing.Namespace, 37 | Name: ing.Name, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ingress/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "strings" 4 | 5 | func ParseSSLAnnotation(sslAnno string) map[string]string { 6 | // alb.networking.{domain}/tls: qq.com=cpaas-system/dex.tls,qq1.com=cpaas-system/dex1.tls 7 | if sslAnno == "" { 8 | return nil 9 | } 10 | rv := make(map[string]string) 11 | parts := strings.Split(sslAnno, ",") 12 | for _, p := range parts { 13 | kv := strings.Split(strings.TrimSpace(p), "=") 14 | if len(kv) != 2 { 15 | return nil 16 | } 17 | k, v := kv[0], kv[1] 18 | if rv[k] != "" && rv[k] != v { 19 | return nil 20 | } 21 | // ["qq.com"]="cpaas-system/dex.tls" 22 | rv[k] = v 23 | } 24 | return rv 25 | } 26 | -------------------------------------------------------------------------------- /ingress/util/util_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseSSLAnnotation(t *testing.T) { 10 | assert.Equal(t, ParseSSLAnnotation("a.com=1,a.com=1"), map[string]string{ 11 | "a.com": "1", 12 | }) 13 | assert.Equal(t, ParseSSLAnnotation("a.com=1,a.com=2"), (map[string]string)(nil)) 14 | } 15 | -------------------------------------------------------------------------------- /migrate/checklist/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/migrate/checklist/README.md -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.0/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header X-Real-IP $remote_addr; 5 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 6 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 7 | proxy_set_header X-Forwarded-Proto $scheme; 8 | proxy_set_header X-Forwarded-Host $http_host; 9 | proxy_set_header X-Forwarded-Port $server_port; 10 | proxy_set_header Upgrade $http_upgrade; 11 | proxy_set_header Connection $connection_upgrade; 12 | 13 | proxy_redirect off; 14 | proxy_http_version 1.1; 15 | 16 | # fix http://jira.alauda.cn/browse/SGHL-142 17 | underscores_in_headers on; 18 | 19 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.0/stream: -------------------------------------------------------------------------------- 1 | # Lua shared dict 2 | lua_code_cache on; 3 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 4 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 5 | lua_shared_dict stream_policy 10m; 6 | lua_shared_dict stream_backend_cache 5m; 7 | lua_shared_dict stream_alb_cache 20m; 8 | lua_shared_dict stream_raw 5m; 9 | lua_shared_dict stream_ipc_shared_dict 1m; 10 | 11 | proxy_connect_timeout 5s; 12 | proxy_timeout 60s; 13 | tcp_nodelay on; 14 | 15 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.0/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | 3 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/grpc_server: -------------------------------------------------------------------------------- 1 | grpc_set_header Content-Type application/grpc; 2 | grpc_socket_keepalive on; 3 | keepalive_requests 1000; 4 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/stream-common: -------------------------------------------------------------------------------- 1 | log_format stream '[$time_local] $remote_addr $protocol $server_port $status $bytes_received $bytes_sent $session_time'; 2 | 3 | access_log /dev/stdout stream; 4 | error_log stderr info; 5 | 6 | lua_code_cache on; 7 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 8 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 9 | 10 | # Lua shared dict 11 | lua_shared_dict stream_policy 10m; 12 | lua_shared_dict stream_backend_cache 5m; 13 | lua_shared_dict stream_alb_cache 20m; 14 | lua_shared_dict stream_raw 5m; 15 | lua_shared_dict stream_ipc_shared_dict 1m; 16 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/stream-tcp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 120s; 4 | tcp_nodelay on; 5 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/stream-udp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 120s; 4 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.10/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.4/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.4/stream: -------------------------------------------------------------------------------- 1 | # Lua shared dict 2 | lua_code_cache on; 3 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 4 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 5 | lua_shared_dict stream_policy 10m; 6 | lua_shared_dict stream_backend_cache 5m; 7 | lua_shared_dict stream_alb_cache 20m; 8 | lua_shared_dict stream_raw 5m; 9 | lua_shared_dict stream_ipc_shared_dict 1m; 10 | 11 | proxy_connect_timeout 5s; 12 | proxy_timeout 60s; 13 | tcp_nodelay on; 14 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.4/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.0/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.0/stream: -------------------------------------------------------------------------------- 1 | # Lua shared dict 2 | lua_code_cache on; 3 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 4 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 5 | lua_shared_dict stream_policy 10m; 6 | lua_shared_dict stream_backend_cache 5m; 7 | lua_shared_dict stream_alb_cache 20m; 8 | lua_shared_dict stream_raw 5m; 9 | lua_shared_dict stream_ipc_shared_dict 1m; 10 | 11 | proxy_connect_timeout 5s; 12 | proxy_timeout 60s; 13 | tcp_nodelay on; 14 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.0/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.9/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.9/stream: -------------------------------------------------------------------------------- 1 | # Lua shared dict 2 | lua_code_cache on; 3 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 4 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 5 | lua_shared_dict stream_policy 10m; 6 | lua_shared_dict stream_backend_cache 5m; 7 | lua_shared_dict stream_alb_cache 20m; 8 | lua_shared_dict stream_raw 5m; 9 | lua_shared_dict stream_ipc_shared_dict 1m; 10 | proxy_next_upstream_tries 5; 11 | 12 | 13 | proxy_connect_timeout 5s; 14 | proxy_timeout 60s; 15 | tcp_nodelay on; 16 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.6.9/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.0/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.0/stream-common: -------------------------------------------------------------------------------- 1 | log_format stream '[$time_local] $remote_addr $protocol $server_port $status $bytes_received $bytes_sent $session_time'; 2 | 3 | access_log /var/log/nginx/stream-access.log stream; 4 | error_log /var/log/nginx/stream-error.log info; 5 | 6 | lua_code_cache on; 7 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 8 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 9 | 10 | # Lua shared dict 11 | lua_shared_dict stream_policy 10m; 12 | lua_shared_dict stream_backend_cache 5m; 13 | lua_shared_dict stream_alb_cache 20m; 14 | lua_shared_dict stream_raw 5m; 15 | lua_shared_dict stream_ipc_shared_dict 1m; 16 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.0/stream-tcp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 60s; 4 | tcp_nodelay on; 5 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.0/stream-udp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 60s; 4 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.0/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.13/http_server: -------------------------------------------------------------------------------- 1 | # fix http://jira.alaudatech.com/browse/DEV-15515, use lua instead 2 | set $custom_host $http_host; 3 | proxy_set_header Host $custom_host; 4 | proxy_set_header Upgrade $http_upgrade; 5 | proxy_set_header Connection $connection_upgrade; 6 | 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | # fix http://jira.alauda.cn/browse/DEVOPS-5309 10 | proxy_set_header X-Forwarded-Proto $scheme; 11 | proxy_set_header X-Forwarded-Host $http_host; 12 | proxy_set_header X-Forwarded-Port $server_port; 13 | 14 | proxy_set_header X-Original-URI $request_uri; 15 | proxy_set_header X-Scheme $scheme; 16 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 17 | proxy_set_header X-Original-Method $request_method; 18 | 19 | proxy_redirect off; 20 | proxy_http_version 1.1; 21 | 22 | # fix http://jira.alauda.cn/browse/SGHL-142 23 | underscores_in_headers on; 24 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.13/stream-common: -------------------------------------------------------------------------------- 1 | 2 | log_format stream '[$time_local] $remote_addr $protocol $server_port $status $bytes_received $bytes_sent $session_time'; 3 | 4 | access_log /dev/stdout stream; 5 | error_log stderr info; 6 | 7 | lua_code_cache on; 8 | lua_package_path '/usr/local/lib/lua/?.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/site/lualib/?.lua;/alb/template/nginx/lua/?.lua;;'; 9 | lua_package_cpath '/usr/local/lib/lua/?.so;;'; 10 | 11 | # Lua shared dict 12 | lua_shared_dict stream_policy 10m; 13 | lua_shared_dict stream_backend_cache 5m; 14 | lua_shared_dict stream_alb_cache 20m; 15 | lua_shared_dict stream_raw 5m; 16 | lua_shared_dict stream_ipc_shared_dict 1m; 17 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.13/stream-tcp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 120s; 4 | tcp_nodelay on; 5 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.13/stream-udp: -------------------------------------------------------------------------------- 1 | proxy_next_upstream_tries 5; 2 | proxy_connect_timeout 5s; 3 | proxy_timeout 120s; 4 | -------------------------------------------------------------------------------- /migrate/checklist/custom/alb/check_cm/cm_map/v3.8.13/upstream: -------------------------------------------------------------------------------- 1 | keepalive 320; 2 | -------------------------------------------------------------------------------- /migrate/checklist/helper.sh: -------------------------------------------------------------------------------- 1 | #!bin/bash 2 | ##日志函数 3 | function log::err() { 4 | printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[31mERROR: \033[0m$@\n" 5 | } 6 | 7 | function log::info() { 8 | printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[32mINFO: \033[0m$@\n" 9 | } 10 | 11 | function list_running_cluster() { 12 | kubectl get clusters.platform.tkestack.io | grep Running | awk '{print $1}' 13 | } 14 | 15 | function kubectl_with_cluster() { 16 | local CLUSTER=$1 17 | shift 18 | if [[ "$CLUSTER" = "global" ]]; then 19 | kubectl $* 20 | return 21 | fi 22 | local CLUSER_ADD=$(kubectl get clusters.platform.tkestack.io $CLUSTER -o jsonpath="{.status.addresses[0].host}") 23 | local CLUSER_PORT=$(kubectl get clusters.platform.tkestack.io $CLUSTER -o jsonpath="{.status.addresses[0].port}") 24 | local CLUSER_CC_NAME=$(kubectl get clusters.platform.tkestack.io $CLUSTER -o jsonpath="{.spec.clusterCredentialRef.name}") 25 | local CLUSTER_TOKEN=$(kubectl get cc $CLUSER_CC_NAME -oyaml | grep token | awk '{print $2}') 26 | KUBECTL="kubectl --insecure-skip-tls-verify=true --server https://$CLUSER_ADD:$CLUSER_PORT --token $CLUSTER_TOKEN" 27 | $KUBECTL $* 28 | } 29 | -------------------------------------------------------------------------------- /migrate/checklist/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | env 3 | set -o pipefail 4 | # set -x 5 | if [[ -n "$2" ]]; then 6 | export prdb_version="$2" 7 | fi 8 | if [[ -n "$3" ]]; then 9 | export target_version="$3" 10 | fi 11 | export backup_dir="./" 12 | source helper.sh 13 | source ./custom/check-alb.sh 14 | eval "$1" 15 | -------------------------------------------------------------------------------- /migrate/checklist/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o pipefail 3 | source helper.sh 4 | source ./custom/check-alb.sh 5 | if [[ "$1" == "run-in-clusters" ]]; then 6 | # may read cluster from env 7 | eval "$2 global" 8 | eval "$2 p1" 9 | else 10 | eval "$@" 11 | fi 12 | -------------------------------------------------------------------------------- /migrate/init-port-info/README.md: -------------------------------------------------------------------------------- 1 | ## 文档 2 | http://confluence.alauda.cn/pages/viewpage.action?pageId=94865661 -------------------------------------------------------------------------------- /migrate/priority/README.md: -------------------------------------------------------------------------------- 1 | # 负载均衡规则优先级迁移 2 | 3 | http://confluence.alauda.cn/pages/viewpage.action?pageId=78809412 4 | 5 | 开放rule的priority字段,范围为1-10,1最高,10最低。 6 | 7 | 历史数据迁移,历史rule用户手动创建的优先级默认为5,ingress翻译来的优先级默认为5。 8 | 9 | 需要兼容业务集群和global版本不同的情况,业务集群未升级时,规则优先级只按内部优先级生效。想使用界面配置优先级必须做升级。 -------------------------------------------------------------------------------- /migrate/v26tov28/README.md: -------------------------------------------------------------------------------- 1 | 原DSL为`(AND (OR (STARTS_WITH URL /kubernetes/) (STARTS_WITH URL /k8s/)) (EQ COOKIE test 12) (RANGE SRC_IP 1 2))` 2 | 3 | 转为json表达为 4 | ```json 5 | [ 6 | { 7 | "values":[ 8 | [ 9 | "STARTS_WITH", 10 | "/kubernetes" 11 | ], 12 | [ 13 | "STARTS_WITH", 14 | "/k8s" 15 | ] 16 | ], 17 | "type":"URL" 18 | }, 19 | { 20 | "values":[ 21 | [ 22 | "EQ", 23 | "12" 24 | ] 25 | ], 26 | "type":"COOKIE", 27 | "key":"test" 28 | }, 29 | { 30 | "values":[ 31 | [ 32 | "RANGE", 33 | "1", 34 | "2" 35 | ] 36 | ], 37 | "type":"SRC_IP" 38 | } 39 | ] 40 | ``` 41 | 42 | 这个脚本用于更新Rule资源的dsl字段为dslx字段。由于过去dsl字段为字符串,因此部分包含了空格或者特殊符号的历史数据可能无法正确转换。需要手动删除后重新创建。 43 | 44 | 传到lua层面需要拟合的dsl结构为 45 | ```json 46 | 47 | [ 48 | "AND", 49 | [ 50 | "OR", 51 | [ 52 | "STARTS_WITH", 53 | "URL", 54 | "/kubernetes" 55 | ], 56 | [ 57 | "STARTS_WITH", 58 | "URL", 59 | "/k8s" 60 | ] 61 | ], 62 | [ 63 | "EQ", 64 | "COOKIE", 65 | "test", 66 | "12" 67 | ], 68 | [ 69 | "RANGE", 70 | "SRC_IP", 71 | "1", 72 | "2" 73 | ] 74 | ] 75 | ``` -------------------------------------------------------------------------------- /pkg/apis/alauda/gateway/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | 3 | // Package v1alpha1 is the v1alpha1 version of the API. 4 | // +groupName=gateway.crd.alauda.io 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /pkg/apis/alauda/gateway/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | "k8s.io/apimachinery/pkg/runtime" 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | ) 8 | 9 | const ( 10 | GroupName = "gateway.crd.alauda.io" 11 | ) 12 | 13 | // SchemeGroupVersion is group version used to register these objects 14 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} 15 | 16 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 17 | func Kind(kind string) schema.GroupKind { 18 | return SchemeGroupVersion.WithKind(kind).GroupKind() 19 | } 20 | 21 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 22 | func Resource(resource string) schema.GroupResource { 23 | return SchemeGroupVersion.WithResource(resource).GroupResource() 24 | } 25 | 26 | var ( 27 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 28 | AddToScheme = SchemeBuilder.AddToScheme 29 | ) 30 | 31 | // Adds the list of known types to Scheme. 32 | func addKnownTypes(scheme *runtime.Scheme) error { 33 | scheme.AddKnownTypes(SchemeGroupVersion, 34 | &TimeoutPolicy{}, 35 | &TimeoutPolicyList{}, 36 | ) 37 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /pkg/apis/alauda/shared/cr.go: -------------------------------------------------------------------------------- 1 | package shared 2 | 3 | import ( 4 | auth_t "alauda.io/alb2/pkg/controller/ext/auth/types" 5 | otelt "alauda.io/alb2/pkg/controller/ext/otel/types" 6 | timeout_t "alauda.io/alb2/pkg/controller/ext/timeout/types" 7 | waft "alauda.io/alb2/pkg/controller/ext/waf/types" 8 | ) 9 | 10 | // struct shared in alb/ft/rule 11 | // +k8s:deepcopy-gen=true 12 | type SharedCr struct { 13 | Otel *otelt.OtelCrConf `json:"otel,omitempty"` 14 | ModeSecurity *waft.WafCrConf `json:"modsecurity,omitempty"` 15 | Auth *auth_t.AuthCr `json:"auth,omitempty"` 16 | Timeout *timeout_t.TimeoutCr `json:"timeout,omitempty"` 17 | } 18 | -------------------------------------------------------------------------------- /pkg/apis/alauda/v1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | 3 | // Package v1alpha1 is the v1alpha1 version of the API. 4 | // +groupName=crd.alauda.io 5 | package v1 6 | -------------------------------------------------------------------------------- /pkg/apis/alauda/v1/register.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | "k8s.io/apimachinery/pkg/runtime" 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | ) 8 | 9 | const ( 10 | GroupName = "crd.alauda.io" 11 | ) 12 | 13 | // SchemeGroupVersion is group version used to register these objects 14 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} 15 | 16 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 17 | func Kind(kind string) schema.GroupKind { 18 | return SchemeGroupVersion.WithKind(kind).GroupKind() 19 | } 20 | 21 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 22 | func Resource(resource string) schema.GroupResource { 23 | return SchemeGroupVersion.WithResource(resource).GroupResource() 24 | } 25 | 26 | var ( 27 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 28 | AddToScheme = SchemeBuilder.AddToScheme 29 | ) 30 | 31 | // Adds the list of known types to Scheme. 32 | func addKnownTypes(scheme *runtime.Scheme) error { 33 | scheme.AddKnownTypes(SchemeGroupVersion, 34 | &ALB2{}, 35 | &ALB2List{}, 36 | &Frontend{}, 37 | &FrontendList{}, 38 | &Rule{}, 39 | &RuleList{}, 40 | ) 41 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/apis/alauda/v2beta1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | 3 | // Package v2beta1 is the v2beta1 version of the API. 4 | // +groupName=crd.alauda.io 5 | package v2beta1 6 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | type ALB2Expansion interface{} 22 | 23 | type FrontendExpansion interface{} 24 | 25 | type RuleExpansion interface{} 26 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v2beta1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v2beta1 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v2beta1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v2beta1/fake/fake_alauda_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v2beta1 "alauda.io/alb2/pkg/client/clientset/versioned/typed/alauda/v2beta1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeCrdV2beta1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeCrdV2beta1) ALB2s(namespace string) v2beta1.ALB2Interface { 32 | return &FakeALB2s{c, namespace} 33 | } 34 | 35 | // RESTClient returns a RESTClient that is used to communicate 36 | // with API server by this client implementation. 37 | func (c *FakeCrdV2beta1) RESTClient() rest.Interface { 38 | var ret *rest.RESTClient 39 | return ret 40 | } 41 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/alauda/v2beta1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v2beta1 20 | 21 | type ALB2Expansion interface{} 22 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/gateway/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/gateway/v1alpha1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/gateway/v1alpha1/fake/fake_gateway_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1alpha1 "alauda.io/alb2/pkg/client/clientset/versioned/typed/gateway/v1alpha1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeGatewayV1alpha1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeGatewayV1alpha1) TimeoutPolicies(namespace string) v1alpha1.TimeoutPolicyInterface { 32 | return &FakeTimeoutPolicies{c, namespace} 33 | } 34 | 35 | // RESTClient returns a RESTClient that is used to communicate 36 | // with API server by this client implementation. 37 | func (c *FakeGatewayV1alpha1) RESTClient() rest.Interface { 38 | var ret *rest.RESTClient 39 | return ret 40 | } 41 | -------------------------------------------------------------------------------- /pkg/client/clientset/versioned/typed/gateway/v1alpha1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | type TimeoutPolicyExpansion interface{} 22 | -------------------------------------------------------------------------------- /pkg/client/listers/alauda/v2beta1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v2beta1 20 | 21 | // ALB2ListerExpansion allows custom methods to be added to 22 | // ALB2Lister. 23 | type ALB2ListerExpansion interface{} 24 | 25 | // ALB2NamespaceListerExpansion allows custom methods to be added to 26 | // ALB2NamespaceLister. 27 | type ALB2NamespaceListerExpansion interface{} 28 | -------------------------------------------------------------------------------- /pkg/client/listers/gateway/v1alpha1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // TimeoutPolicyListerExpansion allows custom methods to be added to 22 | // TimeoutPolicyLister. 23 | type TimeoutPolicyListerExpansion interface{} 24 | 25 | // TimeoutPolicyNamespaceListerExpansion allows custom methods to be added to 26 | // TimeoutPolicyNamespaceLister. 27 | type TimeoutPolicyNamespaceListerExpansion interface{} 28 | -------------------------------------------------------------------------------- /pkg/config/const.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | var Alb2Finalizer = "alb2_instance.finalizer" 4 | -------------------------------------------------------------------------------- /pkg/controller/ext/timeout/types/type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type TimeoutIngress struct { 4 | ProxyConnectTimeoutMs string `annotation:"proxy-connect-timeout" key:"proxy_connect_timeout_ms"` 5 | ProxySendTimeoutMs string `annotation:"proxy-send-timeout" key:"proxy_send_timeout_ms"` 6 | ProxyReadTimeoutMs string `annotation:"proxy-read-timeout" key:"proxy_read_timeout_ms"` 7 | } 8 | 9 | // k8s does not like float type, so we use uint instead 10 | 11 | // +k8s:deepcopy-gen=true 12 | type TimeoutCr struct { 13 | ProxyConnectTimeoutMs *uint `json:"proxy_connect_timeout_ms,omitempty" key:"proxy_connect_timeout_ms" trans:"time_from_string"` 14 | ProxySendTimeoutMs *uint `json:"proxy_send_timeout_ms,omitempty" key:"proxy_send_timeout_ms" trans:"time_from_string"` 15 | ProxyReadTimeoutMs *uint `json:"proxy_read_timeout_ms,omitempty" key:"proxy_read_timeout_ms" trans:"time_from_string"` 16 | } 17 | -------------------------------------------------------------------------------- /pkg/controller/ext/waf/types/waf_type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // +k8s:deepcopy-gen=true 4 | type WafCrConf struct { 5 | Enable bool `json:"enable"` 6 | // +optional 7 | WafConf `json:",inline"` 8 | } 9 | 10 | // +k8s:deepcopy-gen=true 11 | type WafConf struct { 12 | // +optional 13 | TransactionId string `json:"transactionId"` // could be "" 14 | // +optional 15 | UseCoreRules bool `json:"useCoreRules"` 16 | // +optional 17 | UseRecommend bool `json:"useRecommend"` 18 | // +optional 19 | CmRef string `json:"cmRef"` // ns/name#section 20 | } 21 | 22 | type WafInternal struct { 23 | Key string // 要跳转到的 nginx location 24 | Raw WafConf // 其他的waf的配置 25 | Snippet string // nginx location 的配置 26 | } 27 | -------------------------------------------------------------------------------- /pkg/controller/extctl/types/type.go: -------------------------------------------------------------------------------- 1 | package extctl 2 | 3 | import ( 4 | "alauda.io/alb2/config" 5 | m "alauda.io/alb2/controller/modules" 6 | ct "alauda.io/alb2/controller/types" 7 | albv1 "alauda.io/alb2/pkg/apis/alauda/v1" 8 | ngt "alauda.io/alb2/pkg/controller/ngxconf/types" 9 | nv1 "k8s.io/api/networking/v1" 10 | ) 11 | 12 | // ingress/alb/ft/rule 系列的插件。 13 | // TODO 应该能被用在gateway-api 上. 14 | type ExtensionInterface struct { 15 | IngressAnnotationToRule func(ing *nv1.Ingress, rindex int, pindex int, rule *albv1.Rule) 16 | IngressWithFtAnnotationToRule func(ft *albv1.Frontend, ing *nv1.Ingress, rindex int, pindex int, rule *albv1.Rule) 17 | ToInternalRule func(rule *m.Rule, r *ct.InternalRule) 18 | CollectRefs func(*ct.InternalRule, ct.RefMap) 19 | ToPolicy func(*ct.InternalRule, *ct.Policy, ct.RefMap) 20 | UpdateNgxTmpl func(tmpl_cfg *ngt.NginxTemplateConfig, alb *ct.LoadBalancer, cfg *config.Config) 21 | UpdatePolicyAfterUniq func(*ct.PolicyExt) 22 | InitL7Ft func(mft *m.Frontend, cft *ct.Frontend) 23 | NeedL7DefaultPolicy func(cft *ct.Frontend) (bool, string) 24 | InitL7DefaultPolicy func(cft *ct.Frontend, policy *ct.Policy) 25 | InitL4Ft func(mft *m.Frontend, cft *ct.Frontend) 26 | InitL4DefaultPolicy func(cft *ct.Frontend, policy *ct.Policy) 27 | ShouldMergeConfig func() bool 28 | } 29 | -------------------------------------------------------------------------------- /pkg/controller/ngxconf/nginx_param.go: -------------------------------------------------------------------------------- 1 | package ngxconf 2 | 3 | import ( 4 | "os" 5 | "strconv" 6 | 7 | "alauda.io/alb2/config" 8 | . "alauda.io/alb2/pkg/controller/ngxconf/types" 9 | ) 10 | 11 | func checkIPV6(enable bool) bool { 12 | if !enable { 13 | return false 14 | } 15 | if _, err := os.Stat("/proc/net/if_inet6"); err != nil { 16 | if os.IsNotExist(err) { 17 | return false 18 | } 19 | } 20 | return true 21 | } 22 | 23 | const ( 24 | gzipTypes = "application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component" 25 | ) 26 | 27 | func newNginxParam(cfg *config.Config) NginxParam { 28 | ngx := cfg.GetNginxCfg() 29 | 30 | cpu_preset := cfg.GetCpuPreset() 31 | work_limit := cfg.GetWorkerLimit() 32 | if work_limit == 0 { 33 | work_limit = 4 34 | } 35 | return NginxParam{ 36 | EnablePrometheus: ngx.EnablePrometheus, 37 | EnableIPV6: checkIPV6(ngx.EnableIpv6), 38 | EnableHTTP2: ngx.EnableHttp2, 39 | CPUNum: strconv.Itoa(min(cpu_preset, work_limit)), 40 | MetricsPort: cfg.GetMetricsPort(), 41 | Backlog: ngx.BackLog, 42 | EnableGzip: ngx.EnableGzip, 43 | GzipLevel: 5, 44 | GzipMinLength: 256, 45 | GzipTypes: gzipTypes, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/controller/ngxconf/ngxconf.go: -------------------------------------------------------------------------------- 1 | package ngxconf 2 | 3 | import ( 4 | "bytes" 5 | _ "embed" 6 | "os" 7 | "text/template" 8 | 9 | . "alauda.io/alb2/pkg/controller/ngxconf/types" 10 | ) 11 | 12 | //go:embed nginx.tmpl 13 | var NgxTmplEmbed string 14 | 15 | func RenderNgxRaw(config NginxTemplateConfig, tmpl string) (string, error) { 16 | t, err := template.New("nginx").Parse(tmpl) 17 | if err != nil { 18 | return "", err 19 | } 20 | 21 | var tpl bytes.Buffer 22 | if err := t.Execute(&tpl, config); err != nil { 23 | return "", err 24 | } 25 | return tpl.String(), nil 26 | } 27 | 28 | func RenderNgxFromFile(config NginxTemplateConfig, tmplPath string) (string, error) { 29 | tmplBytes, err := os.ReadFile(tmplPath) 30 | if err != nil { 31 | return "", err 32 | } 33 | return RenderNgxRaw(config, string(tmplBytes)) 34 | } 35 | 36 | func RenderNginxConfigEmbed(config NginxTemplateConfig) (string, error) { 37 | return RenderNgxRaw(config, NgxTmplEmbed) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/operator/.dockerignore: -------------------------------------------------------------------------------- 1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file 2 | # Ignore build and test binaries. 3 | bin/ 4 | testbin/ 5 | -------------------------------------------------------------------------------- /pkg/operator/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | bin 9 | testbin/* 10 | 11 | # Test binary, build with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Kubernetes Generated files - skip generated files, except for vendored files 18 | 19 | !vendor/**/zz_generated.* 20 | 21 | # editor and IDE paraphernalia 22 | .idea 23 | *.swp 24 | *.swo 25 | *~ 26 | -------------------------------------------------------------------------------- /pkg/operator/config/const.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type valuePath struct { 4 | Value interface{} 5 | Path []string 6 | } 7 | 8 | var BindNic = valuePath{ 9 | Value: "{}", 10 | Path: []string{"bindNIC"}, 11 | } 12 | 13 | var DEFAULT_ENV = map[string]string{ 14 | "ALB_IMAGE": "alb.img", 15 | "NGINX_IMAGE": "nginx.img", 16 | "LABEL_BASE_DOMAIN": "cpaas.io", 17 | } 18 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/patch/configmap_patch.go: -------------------------------------------------------------------------------- 1 | package patch 2 | 3 | import ( 4 | "context" 5 | 6 | cfg "alauda.io/alb2/pkg/operator/config" 7 | "sigs.k8s.io/controller-runtime/pkg/client" 8 | 9 | corev1 "k8s.io/api/core/v1" 10 | "k8s.io/apimachinery/pkg/types" 11 | "k8s.io/client-go/tools/cache" 12 | ) 13 | 14 | func FindConfigmapPatch(ctx context.Context, cli client.Client, conf *cfg.ALB2Config, operator cfg.OperatorCfg) (hasPatch bool, configMap *corev1.ConfigMap, err error) { 15 | need := false 16 | name, ns := "", "" 17 | for _, p := range conf.Overwrite.Configmap { 18 | if p.Target == "" || p.Target == operator.Version { 19 | need = true 20 | ns, name, err = cache.SplitMetaNamespaceKey(p.Name) 21 | if err != nil { 22 | return false, nil, err 23 | } 24 | } 25 | } 26 | if !need { 27 | return false, nil, nil 28 | } 29 | cfg := &corev1.ConfigMap{} 30 | err = cli.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, cfg) 31 | if err != nil { 32 | return false, nil, err 33 | } 34 | return true, cfg, nil 35 | } 36 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/patch/image_patch.go: -------------------------------------------------------------------------------- 1 | package patch 2 | 3 | import ( 4 | cfg "alauda.io/alb2/pkg/operator/config" 5 | ) 6 | 7 | // TODO 决定一个deployment具体要用那个image,和status中imagepatch字段,应该在一个地方来管理 8 | func GenImagePatch(conf *cfg.ALB2Config, operator cfg.OperatorCfg) (hasPatch bool, alb string, nginx string) { 9 | // 要升级的版本和patch中的版本一致 10 | hasPatch = false 11 | alb = operator.AlbImage 12 | nginx = operator.NginxImage 13 | for _, p := range conf.Overwrite.Image { 14 | if p.Target == "" || p.Target == operator.Version { 15 | if p.Alb != "" { 16 | hasPatch = true 17 | alb = p.Alb 18 | } 19 | if p.Nginx != "" { 20 | hasPatch = true 21 | nginx = p.Nginx 22 | } 23 | } 24 | } 25 | return hasPatch, alb, nginx 26 | } 27 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/configmap/configmap.go: -------------------------------------------------------------------------------- 1 | package configmap 2 | 3 | import ( 4 | v1 "k8s.io/api/core/v1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | type Template struct { 9 | namespace string 10 | name string 11 | } 12 | 13 | func NewTemplate(namespace string, name string) *Template { 14 | return &Template{ 15 | namespace: namespace, 16 | name: name, 17 | } 18 | } 19 | 20 | func (t *Template) Generate(options ...Option) *v1.ConfigMap { 21 | cm := &v1.ConfigMap{ 22 | TypeMeta: metav1.TypeMeta{ 23 | Kind: "ConfigMap", 24 | APIVersion: "v1", 25 | }, 26 | ObjectMeta: metav1.ObjectMeta{ 27 | Name: t.name, 28 | Namespace: t.namespace, 29 | }, 30 | Data: map[string]string{ 31 | "http": HTTP, 32 | "http_server": HTTPSERVER, 33 | "grpc_server": GRPCSERVER, 34 | "stream-common": STREAM_COMMON, 35 | "stream-tcp": STREAM_TCP, 36 | "stream-udp": STREAM_UDP, 37 | "upstream": UPSTREAM, 38 | }, 39 | } 40 | for _, op := range options { 41 | op(cm) 42 | } 43 | return cm 44 | } 45 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/configmap/options.go: -------------------------------------------------------------------------------- 1 | package configmap 2 | 3 | import ( 4 | v1 "k8s.io/api/core/v1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | type Option func(configMap *v1.ConfigMap) 9 | 10 | func WithBindNIC(nic string) Option { 11 | return func(configMap *v1.ConfigMap) { 12 | if configMap == nil { 13 | return 14 | } 15 | if configMap.Data == nil { 16 | configMap.Data = map[string]string{} 17 | } 18 | configMap.Data["bind_nic"] = nic 19 | } 20 | } 21 | 22 | func AddLabel(labels map[string]string) Option { 23 | return func(cm *v1.ConfigMap) { 24 | if cm == nil { 25 | return 26 | } 27 | if cm.Labels == nil { 28 | cm.Labels = map[string]string{} 29 | } 30 | for k, v := range labels { 31 | cm.Labels[k] = v 32 | } 33 | } 34 | } 35 | 36 | func SetOwnerRefs(reference []metav1.OwnerReference) Option { 37 | return func(configMap *v1.ConfigMap) { 38 | if configMap == nil { 39 | return 40 | } 41 | configMap.OwnerReferences = reference 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/gateway/options.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import gv1b1t "sigs.k8s.io/gateway-api/apis/v1" 4 | 5 | type Option func(service *gv1b1t.GatewayClass) 6 | 7 | func AddLabel(labels map[string]string) Option { 8 | return func(ic *gv1b1t.GatewayClass) { 9 | if ic == nil { 10 | return 11 | } 12 | if ic.Labels == nil { 13 | ic.Labels = map[string]string{} 14 | } 15 | for k, v := range labels { 16 | ic.Labels[k] = v 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/portinfo/options.go: -------------------------------------------------------------------------------- 1 | package portinfo 2 | 3 | import ( 4 | v1 "k8s.io/api/core/v1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | type Option func(configMap *v1.ConfigMap) 9 | 10 | func defaultLabel(name string) Option { 11 | return func(cm *v1.ConfigMap) { 12 | if cm == nil { 13 | return 14 | } 15 | cm.Labels = map[string]string{ 16 | "port-info": "true", 17 | "name": name, 18 | } 19 | } 20 | } 21 | 22 | func AddLabel(labels map[string]string) Option { 23 | return func(cm *v1.ConfigMap) { 24 | if cm == nil { 25 | return 26 | } 27 | if cm.Labels == nil { 28 | cm.Labels = map[string]string{} 29 | } 30 | for k, v := range labels { 31 | cm.Labels[k] = v 32 | } 33 | } 34 | } 35 | 36 | func SetOwnerRefs(reference []metav1.OwnerReference) Option { 37 | return func(configMap *v1.ConfigMap) { 38 | if configMap == nil { 39 | return 40 | } 41 | configMap.OwnerReferences = reference 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/portinfo/portinfo.go: -------------------------------------------------------------------------------- 1 | package portinfo 2 | 3 | import ( 4 | "alauda.io/alb2/pkg/operator/toolkit" 5 | v1 "k8s.io/api/core/v1" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | ) 8 | 9 | type Template struct { 10 | namespace string 11 | name string 12 | data string 13 | } 14 | 15 | func NewTemplate(namespace string, name string, data string) *Template { 16 | return &Template{ 17 | namespace: namespace, 18 | name: name, 19 | data: data, 20 | } 21 | } 22 | 23 | func (t *Template) Generate(options ...Option) *v1.ConfigMap { 24 | name := toolkit.FmtKeyBySep("-", t.name, "port-info") 25 | cm := &v1.ConfigMap{ 26 | TypeMeta: metav1.TypeMeta{ 27 | Kind: "ConfigMap", 28 | APIVersion: "v1", 29 | }, 30 | ObjectMeta: metav1.ObjectMeta{ 31 | Name: name, 32 | Namespace: t.namespace, 33 | }, 34 | Data: map[string]string{ 35 | "range": t.data, 36 | }, 37 | } 38 | defaultOptions := []Option{ 39 | defaultLabel(t.name), 40 | } 41 | for _, op := range defaultOptions { 42 | op(cm) 43 | } 44 | for _, op := range options { 45 | op(cm) 46 | } 47 | return cm 48 | } 49 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/rbac/rbac_test.go: -------------------------------------------------------------------------------- 1 | package rbac 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestRoleFromJSON(t *testing.T) { 10 | rules := rulesOrPanic() 11 | t.Logf("role %v", CLUSTER_RULE_YAML) 12 | t.Logf("role %+v", rules) 13 | assert.Equal(t, len(rules) != 0, true) 14 | t.Logf("group %+v", rules[4]) 15 | assert.Equal(t, rules[4].APIGroups[0], "discovery.k8s.io") 16 | } 17 | -------------------------------------------------------------------------------- /pkg/operator/controllers/depl/resources/types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | FMT_ROLE = "%s-clusterrole" 5 | FMT_ROLEBIND = "%s-clusterrolebind" 6 | FMT_SA = "%s-serviceaccount" 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/operator/controllers/scheme.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | albv1 "alauda.io/alb2/pkg/apis/alauda/v1" 5 | albv2 "alauda.io/alb2/pkg/apis/alauda/v2beta1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | coov1 "k8s.io/api/coordination/v1" 8 | corev1 "k8s.io/api/core/v1" 9 | netv1 "k8s.io/api/networking/v1" 10 | rbacv1 "k8s.io/api/rbac/v1" 11 | "k8s.io/apimachinery/pkg/runtime" 12 | gv1 "sigs.k8s.io/gateway-api/apis/v1" 13 | gv1a2t "sigs.k8s.io/gateway-api/apis/v1" 14 | ) 15 | 16 | //nolint:errcheck 17 | func InitScheme(scheme *runtime.Scheme) *runtime.Scheme { 18 | _ = albv2.AddToScheme(scheme) 19 | _ = appsv1.AddToScheme(scheme) 20 | _ = albv1.AddToScheme(scheme) 21 | _ = corev1.AddToScheme(scheme) 22 | _ = netv1.AddToScheme(scheme) 23 | _ = gv1.AddToScheme(scheme) 24 | _ = gv1a2t.AddToScheme(scheme) 25 | _ = rbacv1.AddToScheme(scheme) 26 | _ = coov1.AddToScheme(scheme) 27 | return scheme 28 | } 29 | -------------------------------------------------------------------------------- /pkg/operator/controllers/setup.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "alauda.io/alb2/pkg/operator/config" 5 | "alauda.io/alb2/pkg/operator/controllers/depl" 6 | g "alauda.io/alb2/pkg/operator/controllers/standalone_gateway/gateway" 7 | gc "alauda.io/alb2/pkg/operator/controllers/standalone_gateway/gatewayclass" 8 | "github.com/go-logr/logr" 9 | ctrl "sigs.k8s.io/controller-runtime" 10 | ) 11 | 12 | func Setup(mgr ctrl.Manager, cfg config.OperatorCfg, log logr.Logger) error { 13 | if err := (&depl.ALB2Reconciler{Client: mgr.GetClient(), OperatorCf: cfg, Log: log}).SetupWithManager(mgr); err != nil { 14 | return err 15 | } 16 | if err := (g.NewGatewayReconciler(mgr.GetClient(), cfg, log)).SetupWithManager(mgr); err != nil { 17 | return err 18 | } 19 | if err := (gc.NewGatewayClassReconciler(mgr.GetClient(), cfg, log)).SetupWithManager(mgr); err != nil { 20 | return err 21 | } 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /pkg/operator/controllers/standalone_gateway/gateway/cli_ext.go: -------------------------------------------------------------------------------- 1 | package standalone_gateway 2 | 3 | import ( 4 | "context" 5 | 6 | "alauda.io/alb2/pkg/operator/config" 7 | "github.com/go-logr/logr" 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | ctrcli "sigs.k8s.io/controller-runtime/pkg/client" 10 | gv1b1t "sigs.k8s.io/gateway-api/apis/v1" 11 | ) 12 | 13 | type CliExt struct { 14 | ctrcli.Client 15 | log logr.Logger 16 | cfg config.OperatorCfg 17 | } 18 | 19 | func (c *CliExt) GetGateway(ctx context.Context, req ctrl.Request) (*gv1b1t.Gateway, error) { 20 | g := &gv1b1t.Gateway{} 21 | err := c.Get(ctx, ctrcli.ObjectKey{Namespace: req.Namespace, Name: req.Name}, g) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return g, nil 26 | } 27 | -------------------------------------------------------------------------------- /pkg/operator/controllers/types/const.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | STAND_ALONE_GATEWAY_CLASS = "exclusive-gateway" 5 | FMT_STAND_ALONE_GATEWAY_CLASS_CTL_NAME = "alb2.gateway.%s/exclusive-gateway" 6 | ) 7 | 8 | const FMT_ALB_REF = "alb.%s/alb-ref" 9 | -------------------------------------------------------------------------------- /pkg/operator/toolkit/clustertype.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "context" 5 | 6 | corev1 "k8s.io/api/core/v1" 7 | "sigs.k8s.io/controller-runtime/pkg/client" 8 | ) 9 | 10 | func ClusterTypeIsCCE(cli client.Client, ctx context.Context) (bool, error) { 11 | cm := corev1.ConfigMap{} 12 | err := cli.Get(ctx, client.ObjectKey{Namespace: "kube-public", Name: "global-info"}, &cm) 13 | if err != nil { 14 | return false, err 15 | } 16 | return cm.Data["clusterType"] == "HuaweiCloudCCE", nil 17 | } 18 | -------------------------------------------------------------------------------- /pkg/operator/toolkit/meta.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "strings" 5 | 6 | albv2 "alauda.io/alb2/pkg/apis/alauda/v2beta1" 7 | 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // FmtKeyBySep is return string "key1+sep+key2" 12 | func FmtKeyBySep(sep string, key ...string) string { 13 | return strings.Join(key, sep) 14 | } 15 | 16 | func MakeOwnerRefs(alb2 *albv2.ALB2) []metav1.OwnerReference { 17 | return []metav1.OwnerReference{{ 18 | APIVersion: albv2.SchemeGroupVersion.String(), 19 | Kind: albv2.ALB2Kind, 20 | Name: alb2.GetName(), 21 | UID: alb2.GetUID(), 22 | }} 23 | } 24 | -------------------------------------------------------------------------------- /pkg/operator/toolkit/tools_test.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestYamlToJson(t *testing.T) { 10 | y := ` 11 | antiAffinityKey: system 12 | defaultSSLCert: cpaas-system/dex.tls 13 | defaultSSLStrategy: Both 14 | loadbalancerName: "global-alb2" 15 | metricsPort: 11782 16 | ingress: "true" 17 | albEnable: false 18 | projects: 19 | - cpaas-system 20 | ` 21 | j, err := YamlToJson(y) 22 | assert.NoError(t, err) 23 | t.Logf("%s", j) 24 | assert.Equal(t, j, `{"albEnable":false,"antiAffinityKey":"system","defaultSSLCert":"cpaas-system/dex.tls","defaultSSLStrategy":"Both","ingress":"true","loadbalancerName":"global-alb2","metricsPort":11782,"projects":["cpaas-system"]}`) 25 | } 26 | -------------------------------------------------------------------------------- /pkg/utils/data_trans.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type ResolveAnnotationOpt struct { 9 | Prefix []string // 我们支持多个前缀,这样用户可以用我们自己的前缀来覆盖掉nginx的前缀,这样能保证他们的兼容性 10 | } 11 | 12 | func ResolverStructFromAnnotation(t interface{}, annotation map[string]string, opt ResolveAnnotationOpt) (bool, error) { 13 | t_type := reflect.TypeOf(t).Elem() 14 | t_val := reflect.ValueOf(t).Elem() 15 | has_annotation := false 16 | for i := 0; i < t_type.NumField(); i++ { 17 | t_field := t_type.Field(i) 18 | v_field := t_val.Field(i) 19 | if v_field.Kind() == reflect.Struct && t_field.Anonymous { 20 | has, err := ResolverStructFromAnnotation(v_field.Addr().Interface(), annotation, opt) 21 | if err != nil { 22 | return false, err 23 | } 24 | has_annotation = has_annotation || has 25 | } 26 | 27 | tag := t_field.Tag.Get("annotation") 28 | if tag == "" { 29 | continue 30 | } 31 | default_val := t_field.Tag.Get("default") 32 | // we only support string field to set 33 | if !(v_field.CanSet() && v_field.Kind() == reflect.String) { 34 | continue 35 | } 36 | resolved := false 37 | for _, prefix := range opt.Prefix { 38 | full_key := fmt.Sprintf("%s/%s", prefix, tag) 39 | if value, ok := annotation[full_key]; ok { 40 | v_field.SetString(value) 41 | resolved = true 42 | has_annotation = true 43 | break 44 | } 45 | } 46 | if !resolved { 47 | v_field.SetString(default_val) 48 | } 49 | } 50 | return has_annotation, nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/utils/metrics/metrics.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import "sync" 4 | 5 | var ( 6 | _globalMu sync.RWMutex 7 | _globalM *metrics = nil 8 | ) 9 | 10 | type metrics struct { 11 | data map[string]float64 12 | } 13 | 14 | func init() { 15 | _globalMu.Lock() 16 | defer _globalMu.Unlock() 17 | if _globalM != nil { 18 | return 19 | } 20 | 21 | _globalM = &metrics{data: map[string]float64{}} 22 | } 23 | 24 | // TODO 用 otel span.. 25 | 26 | func Write(key string, value float64) { 27 | _globalMu.Lock() 28 | defer _globalMu.Unlock() 29 | _globalM.data[key] = value 30 | } 31 | 32 | func Read() map[string]float64 { 33 | _globalMu.RLock() 34 | defer _globalMu.RUnlock() 35 | return _globalM.data 36 | } 37 | -------------------------------------------------------------------------------- /pkg/utils/test_utils/ing_utils/ing.go: -------------------------------------------------------------------------------- 1 | package ing_utils 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "alauda.io/alb2/config" 8 | ct "alauda.io/alb2/controller/types" 9 | "alauda.io/alb2/driver" 10 | ing "alauda.io/alb2/ingress" 11 | . "alauda.io/alb2/pkg/utils/test_utils" 12 | "github.com/go-logr/logr" 13 | "k8s.io/client-go/rest" 14 | ) 15 | 16 | func SyncIngressAndGetPolicyFromK8s(rest *rest.Config, ns, name string, log logr.Logger) (*ct.NgxPolicy, error) { 17 | ctx := context.Background() 18 | cfg := config.Mock(name, ns) 19 | drv, err := driver.NewDriver(driver.DrvOpt{Ctx: ctx, Cf: rest, Opt: driver.Cfg2opt(cfg)}) 20 | if err != nil { 21 | return nil, err 22 | } 23 | ing_ctl := ing.NewController(drv, drv.Informers, cfg, log) 24 | ing_ctl.SyncAll() 25 | time.Sleep(1 * time.Second) 26 | go ing_ctl.RunWorker() 27 | for i := 0; i < 10; i++ { 28 | if ing_ctl.GetWorkqueueLen() == 0 { 29 | break 30 | } 31 | time.Sleep(1 * time.Second) // wait rule sync 32 | } 33 | time.Sleep(3 * time.Second) // wait rule sync 34 | policy, err := GetPolicy(PolicyGetCtx{ 35 | Ctx: ctx, Name: name, Ns: ns, Drv: drv, L: log, 36 | Cfg: cfg, 37 | }) 38 | if err != nil { 39 | return nil, err 40 | } 41 | return policy, nil 42 | } 43 | -------------------------------------------------------------------------------- /pkg/utils/test_utils/mock_svc.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import otu "alauda.io/alb2/utils/test_utils" 4 | 5 | type MockSvc struct { 6 | Ns string 7 | Name string 8 | Port []int 9 | Ep []string 10 | } 11 | 12 | func (m MockSvc) GenYaml() string { 13 | return otu.Template(` 14 | apiVersion: v1 15 | kind: Service 16 | metadata: 17 | name: {{.name}} 18 | namespace: {{.ns}} 19 | spec: 20 | clusterIP: 10.0.0.254 21 | internalTrafficPolicy: Cluster 22 | sessionAffinity: None 23 | type: ClusterIP 24 | ipFamilies: 25 | - IPv4 26 | ipFamilyPolicy: SingleStack 27 | ports: 28 | {{ range $p := .port }} 29 | - name: port-{{$p}} 30 | port: {{$p}} 31 | protocol: TCP 32 | targetPort: {{$p}} 33 | {{ end }} 34 | --- 35 | apiVersion: v1 36 | kind: Endpoints 37 | metadata: 38 | name: {{.name}} 39 | namespace: {{.ns}} 40 | subsets: 41 | {{ range $ip := .ep }} 42 | - addresses: 43 | - ip: {{$ip}} 44 | ports: 45 | {{ range $p := $.port }} 46 | - name: port-{{$p}} 47 | port: {{$p}} 48 | protocol: TCP 49 | {{- end -}} 50 | {{- end -}} 51 | `, map[string]interface{}{"name": m.Name, "ns": m.Ns, "port": m.Port, "ep": m.Ep}) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/utils/test_utils/ngxconf_parser_ext_test.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseNgxConfig(t *testing.T) { 10 | cfg := ` 11 | 12 | events { 13 | multi_accept on; 14 | worker_connections 51200; 15 | } 16 | 17 | http { 18 | server { 19 | listen 127.0.0.1:81; 20 | listen 192.168.2.3:81; 21 | } 22 | } 23 | 24 | stream { 25 | server { 26 | listen 127.0.0.1:80 udp; 27 | listen 192.168.2.3:80 udp; 28 | } 29 | server { 30 | listen 127.0.0.1:80; 31 | listen 192.168.2.3:80; 32 | } 33 | } 34 | ` 35 | listen, err := PickStreamServerListen(cfg) 36 | assert.NoError(t, err) 37 | assert.Equal(t, listen[0], "127.0.0.1:80 udp") 38 | assert.Equal(t, listen[1], "192.168.2.3:80 udp") 39 | assert.Equal(t, listen[2], "127.0.0.1:80") 40 | assert.Equal(t, listen[3], "192.168.2.3:80") 41 | assert.Equal(t, len(listen), 4) 42 | 43 | listen, err = PickHttpServerListen(cfg) 44 | assert.NoError(t, err) 45 | assert.Equal(t, listen[0], "127.0.0.1:81") 46 | assert.Equal(t, listen[1], "192.168.2.3:81") 47 | assert.Equal(t, len(listen), 2) 48 | } 49 | -------------------------------------------------------------------------------- /pkg/utils/util.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "fmt" 7 | "strings" 8 | 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | func ToBoolOr(x string, backup bool) bool { 13 | if x == "" { 14 | return backup 15 | } 16 | return strings.ToLower(strings.TrimSpace(x)) == "true" 17 | } 18 | 19 | func MergeMap(a map[string]string, b map[string]string) map[string]string { 20 | ret := map[string]string{} 21 | for k, v := range a { 22 | ret[k] = v 23 | } 24 | for k, v := range b { 25 | ret[k] = v 26 | } 27 | return ret 28 | } 29 | 30 | func HashBytes(s []byte) string { 31 | h := sha256.New() 32 | h.Write(s) 33 | return hex.EncodeToString(h.Sum(nil)) 34 | } 35 | 36 | func Hash(s string) string { 37 | h := sha256.New() 38 | h.Write([]byte(s)) 39 | return hex.EncodeToString(h.Sum(nil)) 40 | } 41 | 42 | func ParseStringToObjectKey(key string) (client.ObjectKey, error) { 43 | parts := strings.Split(key, "/") 44 | if len(parts) != 2 { 45 | return client.ObjectKey{}, fmt.Errorf("invalid key format: %s", key) 46 | } 47 | return client.ObjectKey{ 48 | Namespace: parts[0], 49 | Name: parts[1], 50 | }, nil 51 | } 52 | -------------------------------------------------------------------------------- /scripts/alb-ai-actions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function alb-ai-review() { 4 | # 为ai-review而优化的commit workflow 5 | # 不在两个commit中改同一个文件 6 | # commit message 作为prompt的一部分 7 | local commit=$1 8 | if [ -z "$commit" ]; then 9 | commit=$(git log --pretty=format:"%H %s" origin/master..HEAD | fzf | awk '{print $1}') 10 | fi 11 | local msg=$(git show -s --format=%s $commit | sed 's/\n/_/g' | sed 's/\s/_/g' | sed 's|/|_|g') 12 | echo "review $commit $msg" 13 | local full_msg=$(git show -s --format=%B $commit) 14 | local prompt=$( 15 | cat </dev/null 2>&1 29 | local p="./.review/$commit-$msg.review.prompt" 30 | echo "$prompt" >$p 31 | git show $commit >>$p 32 | echo "$p $(ls -alh $p)" 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /scripts/alb-checklist-actions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function alb-sync-to-checklist() { 4 | local target="$1" 5 | for p in ./migrate/checklist/custom/*; do 6 | md5sum $p 7 | cp -r $p $target/checklist/custom/ 8 | done 9 | echo "=====" 10 | for p in $target/checklist/custom/*; do 11 | md5sum $p 12 | done 13 | } 14 | 15 | function alb-sync-from-checklist() { 16 | local target="$1" 17 | for p in $target/checklist/custom/*; do 18 | md5sum $p 19 | cp $p ./migrate/checklist/custom/ 20 | done 21 | echo "=====" 22 | for p in ./migrate/checklist/custom/*; do 23 | md5sum $p 24 | done 25 | } 26 | 27 | function alb-checklist-test() ( 28 | ginkgo -v ./test/checklist 29 | ) 30 | -------------------------------------------------------------------------------- /scripts/alb-dev-actions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC2046,SC2086,SC1091,SC2005 3 | 4 | export GOPROXY=https://goproxy.cn,https://build-nexus.alauda.cn/repository/golang,direct 5 | 6 | function _current_file() { 7 | local cf="${BASH_SOURCE[0]}" 8 | if [ -z "$cf" ]; then 9 | cf="$1" 10 | fi 11 | echo $cf 12 | } 13 | 14 | function _alb_dir() ( 15 | echo $(dirname $(cd $(dirname $(_current_file $1)) && pwd)) 16 | ) 17 | 18 | CUR_ALB_BASE=$(_alb_dir "$0") 19 | 20 | source $CUR_ALB_BASE/scripts/alb-test-actions.sh 21 | source $CUR_ALB_BASE/scripts/alb-lint-actions.sh 22 | source $CUR_ALB_BASE/scripts/alb-build-actions.sh 23 | source $CUR_ALB_BASE/scripts/alb-env-actions.sh 24 | source $CUR_ALB_BASE/scripts/alb-codegen-actions.sh 25 | source $CUR_ALB_BASE/scripts/alb-perf-actions.sh 26 | source $CUR_ALB_BASE/template/actions/alb-nginx.sh 27 | source $CUR_ALB_BASE/scripts/alb-github-actions.sh 28 | source $CUR_ALB_BASE/scripts/alb-ai-actions.sh 29 | 30 | function alb-dev-install() ( 31 | # yq => yq (https://github.com/mikefarah/yq/) version > 4 32 | return 33 | ) 34 | 35 | function alb-list-todo-all() ( 36 | rg TODO 37 | ) 38 | 39 | function alb-list-todo-cur() ( 40 | git diff $(git merge-base master HEAD)..HEAD | grep -i "TODO" 41 | ) 42 | 43 | function alb-replace-alb() ( 44 | alb-static-build 45 | local alb_pod=$(kubectl get po -n cpaas-system --no-headers | grep $1 | awk '{print $1}') 46 | kubectl cp $PWD/bin/alb cpaas-system/$alb_pod:/alb/ctl/alb -c alb2 47 | ) 48 | -------------------------------------------------------------------------------- /scripts/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 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 | -------------------------------------------------------------------------------- /scripts/custom-ci-action.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function init() { 4 | yum update 5 | yum install docker 6 | # make sure docker work 7 | docker pull registry.alauda.cn:60080/acp/alb-nginx:v3.12.2 8 | # musl 9 | # https://rhel.pkgs.org/7/forensics-x86_64/musl-libc-1.2.1-1.el7.x86_64.rpm.html 10 | # kind 11 | # helm 12 | # kubectl 13 | # yq 14 | 15 | } 16 | -------------------------------------------------------------------------------- /scripts/go-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pwd 3 | sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories 4 | apk add bash curl jq 5 | bash -c 'ALB=$PWD;source ./scripts/alb-dev-actions.sh;alb-test-all-in-ci-golang' 6 | -------------------------------------------------------------------------------- /scripts/kubescape.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | res = JSON.parse(fs.readFileSync('./results.json', 'utf8')) 3 | out = [] 4 | for (i of res.results) { 5 | cs = [] 6 | for (c of i.controls) { 7 | if (c.status.status != "passed") { 8 | // console.log(c.status); 9 | cs.push(c) 10 | } 11 | } 12 | i.controls = cs 13 | if (cs.length > 0) { 14 | out.push(i) 15 | } 16 | } 17 | console.log(JSON.stringify(out, null, 4)); -------------------------------------------------------------------------------- /scripts/nginx-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pwd 3 | sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories 4 | apk add bash curl jq 5 | bash -c 'ALB=$PWD;source ./template/actions/alb-nginx.sh;alb-test-all-in-ci-nginx' 6 | -------------------------------------------------------------------------------- /scripts/run-like-ci-go.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | # proxy="" 4 | # if [ -n "$USE_PROXY" ]; then 5 | # proxy="--network=host -e http_proxy=$HTTP_PROXY -e https_proxy=$HTTPS_PROXY " 6 | # fi 7 | base=${1-$(cat ./Dockerfile | grep GO_BUILD_BASE | awk -F = '{print $2}')} 8 | echo "base $base" 9 | platform=${MATRIX_PLATFORM:-linux/amd64} 10 | echo "platform -- $platform --" 11 | docker run --network=host -v $PWD:/acp-alb-test --platform $platform -e ALB_ONLINE=$ALB_ONLINE -t $base sh -c "cd /acp-alb-test ;/acp-alb-test/scripts/go-test.sh" 12 | -------------------------------------------------------------------------------- /scripts/run-like-ci-kind.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function kind-e2e-local() ( 4 | go test -c alauda.io/alb2/test/kind/e2e 5 | mv ./test.test ./alb-kind-e2e 6 | export ALB_SUFFIX=ka 7 | echo $ALB_SUFFIX 8 | md5sum ./alb-kind-e2e 9 | export ALB_KIND_E2E_CHART=v3.13.0-alpha.11 10 | export ALB_CI_ROOT=/tmp/alb-kind 11 | mkdir -p $ALB_CI_ROOT 12 | local base="$ALB_CI_ROOT/$ALB_SUFFIX" 13 | mkdir -p $base 14 | mv ./alb-kind-e2e $base 15 | cd $base 16 | export ALB_TEST_BASE=$base 17 | ./alb-kind-e2e 18 | ) 19 | 20 | kind-e2e-local $@ 21 | -------------------------------------------------------------------------------- /scripts/run-like-ci-nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # test current nginx 3 | # we should build a nginx image first then use this image to test. 4 | tag=$(yq '.global.images.nginx.tag' ./deploy/chart/alb/values.yaml) 5 | image=build-harbor.alauda.cn/acp/alb2:$tag 6 | if [ -n "$1" ] && [ "$1" != "cur" ]; then 7 | image="$1" 8 | fi 9 | # image=alb-nginx:test 10 | 11 | platform=${MATRIX_PLATFORM:-linux/amd64} 12 | echo "platform $platform" 13 | if [ "$2" == "shell" ]; then 14 | docker run --user root --network=host --platform $platform -v $PWD:/acp-alb-test -it $image sh 15 | else 16 | docker run --user root --network=host --platform $platform -v $PWD:/acp-alb-test -t $image sh -c 'cd /acp-alb-test ;/acp-alb-test/scripts/nginx-test.sh' 17 | fi 18 | -------------------------------------------------------------------------------- /scripts/yaml/crds/extra/mock/clustercert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: clustercredentials.platform.tkestack.io 6 | spec: 7 | group: platform.tkestack.io 8 | names: 9 | kind: ClusterCredential 10 | listKind: ClusterCredentialList 11 | plural: clustercredentials 12 | shortNames: 13 | - cc 14 | singular: clustercredential 15 | scope: Cluster 16 | versions: 17 | - name: v1 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | apiVersion: 23 | type: string 24 | kind: 25 | type: string 26 | metadata: 27 | type: object 28 | spec: 29 | type: object 30 | properties: 31 | token: 32 | type: string 33 | served: true 34 | storage: true -------------------------------------------------------------------------------- /scripts/yaml/crds/v1beta1/alb2-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: alaudaloadbalancer2.crd.alauda.io 5 | spec: 6 | group: crd.alauda.io 7 | version: v1 8 | versions: 9 | - name: v1 10 | served: true 11 | storage: true 12 | scope: Namespaced 13 | subresources: 14 | status: {} 15 | names: 16 | plural: alaudaloadbalancer2 17 | singular: alaudaloadbalancer2 18 | kind: ALB2 19 | shortNames: 20 | - alb2 21 | validation: 22 | openAPIV3Schema: 23 | properties: 24 | spec: 25 | description: spec contains specification parameters for a alb2 resource 26 | type: object 27 | properties: 28 | address: 29 | description: address is used to shown access address if no domain 30 | type: string 31 | bind_address: 32 | description: deprecated field 33 | type: string 34 | type: 35 | description: deprecated field 36 | type: string 37 | domains: 38 | description: deprecated field 39 | anyOf: 40 | - type: array 41 | items: 42 | type: string 43 | - type: null -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # sonar.projectVersion=v3.12-1-g7651640 2 | # if you want disabled the DTD verification for a proxy problem for example, true by default 3 | sonar.coverage.dtdVerification=false 4 | # JUnit like test report, default value is test.xml 5 | sonar.sources=./ 6 | sonar.test=./ 7 | sonar.exclusions=test/**,**/*_test.go,pkg/apis/**,pkg/client/** 8 | sonar.test.inclusions=./**/*_test.go 9 | sonar.test.exclusions=vendor/** 10 | # sonar.golint.reportPath=report.xml 11 | # sonar.coverage.reportPath=coverage.xml 12 | # sonar.test.reportPath=test.xml 13 | sonar.go.coverage.reportPaths=coverage.txt 14 | # sonar.host.url=https://build-sonar.alauda.cn 15 | # sonar.branch.name=master 16 | # sonar.login=f09bc48196cea04ffce476f1c178055b8da2820e 17 | sonar.links.scm=https://gitlab-ce.alauda.cn/container-platform/alb2 18 | -------------------------------------------------------------------------------- /template/Dockerfile.debug: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | RUN echo "Hello, World!" 3 | -------------------------------------------------------------------------------- /template/actions/dev.actions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function ang-build-nginx-image() { 4 | local tag="local" 5 | if [[ -n "$1" ]]; then 6 | tag=$1 7 | fi 8 | echo "build alb-nginx local" 9 | docker build -t build-harbor.alauda.cn/acp/alb-nginx:$tag -f ./template/Dockerfile . 10 | docker tag build-harbor.alauda.cn/acp/alb-nginx:$tag registry.alauda.cn:60080/acp/alb-nginx:$tag 11 | } 12 | 13 | function ang-local-test() { 14 | if [ -d ./.t ]; then 15 | sudo rm -rf ./.t 16 | fi 17 | docker run --user root -it -e SKIP_INSTALL_NGINX_TEST_DEP=true -v $PWD/.t:/t/ -v $PWD/template/nginx/:/alb/nginx/ -v $PWD:/acp-alb-test build-harbor.alauda.cn/acp/alb-nginx-tester:local sh -c 'cd /acp-alb-test ;/acp-alb-test/scripts/nginx-test.sh' 18 | } 19 | 20 | function ang-start() ( 21 | mkdir -p ./.ang/logs 22 | local alb=$PWD 23 | local chaos=$alb/template/actions/chaos 24 | cd ./.ang 25 | cp $chaos/alb.nginx.conf ./ 26 | ln -s $alb ./alb2 27 | configmap_to_file $alb/template/tweak 28 | sed -i '/proxy_send*/d' $alb/template/tweak/http.conf 29 | sed -i '/proxy_read*/d' $alb/template/tweak/http.conf 30 | export SYNC_POLICY_INTERVAL=1 31 | export CLEAN_METRICS_INTERVAL=2592000 32 | export NEW_POLICY_PATH=$chaos/policy.json 33 | export DEFAULT_SSL_STRATEGY=NEVER 34 | export INGRESS_HTTPS_PORT=443 35 | nginx -p $PWD -c $PWD/alb.nginx.conf 36 | return 37 | ) 38 | 39 | function nb-start-alb() { 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /template/actions/test-nginx-in-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CFD="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" 3 | ALB=$(realpath $CFD/../../) 4 | source $CFD/alb-nginx.sh 5 | 6 | test-nginx-in-ci 7 | -------------------------------------------------------------------------------- /template/chaos/break/README.md: -------------------------------------------------------------------------------- 1 | 测试在不同阶段中断对alb重试的影响 -------------------------------------------------------------------------------- /template/chaos/tl502/README.md: -------------------------------------------------------------------------------- 1 | https://jira.alauda.cn/browse/ACP-30564 2 | 测试 3 | - 在发了rst之后会不会继续发包 4 | - 在收到了rst之后后不会报502 5 | 6 | 7 | wrk -d3s -c1 -t1 -s ./x.lua http://127.0.0.1 -- 6 8 | -------------------------------------------------------------------------------- /template/chaos/tl502/demo.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | daemon off; 3 | pid nginx.pid; 4 | env POD_NAME; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | access_log /dev/stdout ; 12 | error_log /dev/stdout info; 13 | server { 14 | listen 80; 15 | listen [::]:80; 16 | location / { 17 | content_by_lua_block { 18 | local h, err = ngx.req.get_headers() 19 | if err ~=nil then 20 | ngx.say("err: "..tostring(err)) 21 | end 22 | for k, v in pairs(h) do 23 | ngx.say(tostring(k).." : "..tostring(v)) 24 | end 25 | ngx.say("http client-ip "..ngx.var.remote_addr.." client-port "..ngx.var.remote_port.." server-ip "..ngx.var.server_addr.." server-port "..ngx.var.server_port) 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /template/chaos/tl502/test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | local u = require "util" 3 | 4 | function _M.as_backend() 5 | ngx.say "ok" 6 | 7 | end 8 | function _M.as_backend_1_0() 9 | ngx.say "ok" 10 | end 11 | function _M.as_backend_1_1() 12 | ngx.say "ok" 13 | end 14 | 15 | function _M.test() 16 | -- do 17 | -- local httpc = require"resty.http".new() 18 | -- local res, err = httpc:request("http://127.0.0.1:80/1_0/1") 19 | -- u.logs(res, err) 20 | -- local res, err = httpc:request("http://127.0.0.1:80/1_0/2") 21 | -- u.logs(res, err) 22 | -- end 23 | -- do 24 | -- local httpc = require"resty.http".new() 25 | -- local res, err = httpc:request("http://127.0.0.1:80/1_1/1") 26 | -- u.logs(res, err) 27 | -- local res, err = httpc:request_uri("http://127.0.0.1:80/1_1/2") 28 | -- u.logs(res, err) 29 | -- end 30 | do 31 | local httpc = require"resty.http".new() 32 | local res, err = httpc:request_uri("http://127.0.0.1:80/default/1", {method = "POST", body = "xx"}) 33 | u.logs(res, err) 34 | local res, err = httpc:request_uri("http://127.0.0.1:80/default/2", {method = "POST", body = "xx"}) 35 | u.logs(res, err) 36 | 37 | ngx.sleep(3000) 38 | end 39 | end 40 | return _M 41 | -------------------------------------------------------------------------------- /template/nginx/lua/README.md: -------------------------------------------------------------------------------- 1 | ## how to write test 2 | write test under ALB/alb-nginx/t 3 | ALB/alb-nginx/t/ping.t is a good example 4 | 5 | ## how to lint/format 6 | use alb-lua-format-check action on alb-dev-action.sh. 7 | update TOUCHED_LUA_FILE when you update a lua file. 8 | 9 | ## how to write doc 10 | https://keplerproject.github.io/luadoc/manual.html 11 | -------------------------------------------------------------------------------- /template/nginx/lua/balancer/alb_chash.lua: -------------------------------------------------------------------------------- 1 | local balancer_resty = require "balancer.resty" 2 | local resty_chash = require "resty.chash" 3 | local common = require "utils.common" 4 | local bc = require "balancer.common" 5 | 6 | local _M = balancer_resty:new({ factory = resty_chash, name = "chash" }) 7 | 8 | function _M.new(self, backend) 9 | local nodes = bc.get_nodes(backend) 10 | local o = { 11 | instance = self.factory:new(nodes), 12 | } 13 | if backend["session_affinity_policy"] == "sip-hash" then 14 | o.hash_by = "$remote_addr" 15 | end 16 | setmetatable(o, self) 17 | self.__index = self 18 | return o 19 | end 20 | 21 | function _M.balance(self) 22 | local key = common.lua_ngx_var(self.hash_by) 23 | return self.instance:find(key) 24 | end 25 | 26 | return _M 27 | -------------------------------------------------------------------------------- /template/nginx/lua/balancer/common.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | -- { 3 | -- "mode": "http", 4 | -- "session_affinity_attribute": "", 5 | -- "name": "calico-new-yz-alb-09999-eb1a18d0-8d44-4100-bbb8-93db3c02c482", 6 | -- "session_affinity_policy": "", 7 | -- "backends": [ 8 | -- { 9 | -- "ns": "default", 10 | -- "svc": "xx", 11 | -- "port": 80, 12 | -- "address": "10.16.12.11", 13 | -- "weight": 100 14 | -- } 15 | -- ] 16 | -- } 17 | 18 | function _M.node_key(ep) 19 | return ep.address .. ":" .. ep.port 20 | end 21 | function _M.get_nodes(backend) 22 | local nodes = {} 23 | 24 | for _, endpoint in ipairs(backend.backends) do 25 | local endpoint_string = _M.node_key(endpoint) 26 | nodes[endpoint_string] = endpoint.weight 27 | end 28 | return nodes 29 | end 30 | 31 | return _M 32 | -------------------------------------------------------------------------------- /template/nginx/lua/balancer/resty.lua: -------------------------------------------------------------------------------- 1 | local common = require "utils.common" 2 | local bc = require "balancer.common" 3 | local new_tab = require "table.new" 4 | 5 | local string_format = string.format 6 | local ngx_log = ngx.log 7 | local INFO = ngx.INFO 8 | 9 | local _M = {} 10 | 11 | function _M.new(self, o) 12 | o = o or {} 13 | setmetatable(o, self) 14 | self.__index = self 15 | return o 16 | end 17 | 18 | local function init_peer_map(backend) 19 | local peer_map = new_tab(0, #backend.backends) 20 | for i, node in ipairs(backend.backends) do 21 | peer_map[bc.node_key(node)] = i 22 | end 23 | return peer_map 24 | end 25 | 26 | function _M.sync(self, backend) 27 | local nodes = bc.get_nodes(backend) 28 | self.backend = backend 29 | if self.backend.peer_map == nil then 30 | self.backend.peer_map = init_peer_map(backend) 31 | end 32 | local changed = not common.table_equals(self.instance.nodes, nodes) 33 | if not changed then 34 | return 35 | end 36 | 37 | ngx_log(INFO, string_format("[%s] nodes have changed for backend %s", self.name, backend.name)) 38 | self.backend.peer_map = init_peer_map(backend) 39 | self.instance:reinit(nodes) 40 | end 41 | 42 | function _M.get_peer_conf(self, peer) 43 | local index = self.backend.peer_map[peer] 44 | return self.backend.backends[index] 45 | end 46 | 47 | return _M 48 | -------------------------------------------------------------------------------- /template/nginx/lua/balancer/round_robin.lua: -------------------------------------------------------------------------------- 1 | local balancer_resty = require "balancer.resty" 2 | local resty_roundrobin = require "resty.roundrobin" 3 | local bc = require "balancer.common" 4 | 5 | local _M = balancer_resty:new({ factory = resty_roundrobin, name = "round_robin" }) 6 | 7 | function _M.new(self, backend) 8 | local nodes = bc.get_nodes(backend) 9 | local o = { 10 | instance = self.factory:new(nodes), 11 | } 12 | setmetatable(o, self) 13 | self.__index = self 14 | return o 15 | end 16 | 17 | function _M.balance(self) 18 | return self.instance:find() 19 | end 20 | 21 | return _M 22 | -------------------------------------------------------------------------------- /template/nginx/lua/config/README.md: -------------------------------------------------------------------------------- 1 | this module include thing related to push our policy.json to each worker's mlcache. 2 | -------------------------------------------------------------------------------- /template/nginx/lua/config/conf.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local os_getenv = os.getenv 3 | 4 | local _M = {} 5 | 6 | _M.default_ssl_strategy = os_getenv("DEFAULT_SSL_STRATEGY") 7 | _M.default_https_port = os_getenv("INGRESS_HTTPS_PORT") 8 | 9 | return _M 10 | -------------------------------------------------------------------------------- /template/nginx/lua/ctx/alb_ctx.lua: -------------------------------------------------------------------------------- 1 | --- per request ctx 2 | 3 | local _M = {} 4 | local str_sub = string.sub 5 | local var_proxy = require "ctx.var_proxy" 6 | 7 | ---@class BackendConf 8 | ---@field address string 9 | ---@field port number 10 | ---@field weight number 11 | ---@field svc string? 12 | ---@field ns string? 13 | 14 | ---@class PeerConf 15 | ---@field peer string 16 | ---@field conf BackendConf the policy.backend_groups[upstream].backends[current_backend_index] 17 | 18 | 19 | ---@class AlbCtx 20 | ---@field matched_policy Policy 21 | ---@field send_count number retry_count 22 | ---@field peer PeerConf valid only after the balance phase 23 | ---@field var table var proxy 24 | ---@field otel OtelCtx? 25 | ---@field auth AuthCtx? 26 | 27 | ---@param ctx AlbCtx 28 | function _M.get_last_upstream_status(ctx) 29 | -- $upstream_status maybe including multiple status, only need the last one 30 | return tonumber(str_sub(ctx.var["upstream_status"] or "", -3)) 31 | end 32 | 33 | ---@return AlbCtx 34 | function _M.new() 35 | return { 36 | var = var_proxy.new(), 37 | send_count = 0, 38 | matched_policy = nil, 39 | } 40 | end 41 | 42 | ---@return AlbCtx 43 | function _M.get_alb_ctx() 44 | return ngx.ctx.alb_ctx 45 | end 46 | 47 | return _M 48 | -------------------------------------------------------------------------------- /template/nginx/lua/error.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local _M = {} 3 | local ngx = ngx 4 | local common = require "utils.common" 5 | local subsys = require "utils.subsystem" 6 | 7 | local ErrReason = "X-ALB-ERR-REASON" 8 | 9 | _M.UnknowStickyPolicy = "UnknowStickyPolicy" 10 | _M.InvalidUpstream = "InvalidUpstream" 11 | _M.InvalidBalancer = "InvalidBalancer" 12 | _M.BackendError = "BackendError" 13 | _M.TimeoutViaAlb = "TimeoutViaAlb" 14 | _M.TimeoutViaBackend = "TimeoutViaBackend" 15 | _M.AUTHFAIL = "AuthFail" 16 | 17 | ---comment 18 | -- exit with code 500 Internal Server Error 19 | ---@param reason string 20 | ---@param msg? string 21 | function _M.exit(reason, msg) 22 | _M.exit_with_code(reason, msg, ngx.ERROR) 23 | end 24 | 25 | function _M.exit_with_code(reason, msg, code) 26 | if msg ~= nil then 27 | reason = reason .. " : " .. tostring(msg) 28 | end 29 | ngx.log(ngx.ERR, reason) 30 | if subsys.is_http_subsystem() then 31 | ngx.header[ErrReason] = reason 32 | ngx.ctx.is_alb_err = true 33 | ngx.status = code 34 | if ngx.ctx.alb_ctx.var["http_cpaas_trace"] == "true" then 35 | ngx.header["x-cpaas-trace"] = common.json_encode(ngx.ctx.alb_ctx.var.trace, false) 36 | end 37 | ngx.exit(ngx.HTTP_OK) 38 | end 39 | if subsys.is_stream_subsystem() then 40 | ngx.exit(ngx.ERROR) 41 | end 42 | end 43 | 44 | function _M.http_backend_error(_, msg) 45 | ngx.header[ErrReason] = _M.BackendError .. " : " .. tostring(msg) 46 | end 47 | 48 | return _M 49 | -------------------------------------------------------------------------------- /template/nginx/lua/l4_preread.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local ngx = ngx 3 | local ngx_var = ngx.var 4 | local ngx_log = ngx.log 5 | local e = require("error") 6 | 7 | local upstream = require "match_engine.upstream" 8 | local albctx = require "ctx.alb_ctx" 9 | 10 | local subsystem = ngx.config.subsystem 11 | ngx.ctx.alb_ctx = albctx.new() 12 | local port = tonumber(ngx_var.server_port) 13 | if port == nil then 14 | local msg = "invalid server_port " .. tostring(ngx_var.server_port) 15 | return e.exit(e.InvalidUpstream, msg) 16 | end 17 | 18 | local t_upstream, matched_policy, errmsg = upstream.get_upstream(subsystem, ngx_var.protocol, port) 19 | 20 | if t_upstream == nil then 21 | local msg = "alb upstream not found " 22 | return e.exit(e.InvalidUpstream, msg) 23 | end 24 | 25 | if matched_policy == nil then 26 | local msg = "alb policy not found" 27 | return e.exit(e.InvalidUpstream, msg) 28 | end 29 | 30 | if t_upstream ~= nil then 31 | ngx.ctx.upstream = t_upstream 32 | end 33 | 34 | ngx.ctx.matched_policy = matched_policy 35 | ngx.ctx.alb_ctx.matched_policy = matched_policy 36 | 37 | if errmsg ~= nil then 38 | ngx_log(ngx.ERR, errmsg) 39 | e.exit(e.InvalidUpstream, errmsg) 40 | end 41 | -------------------------------------------------------------------------------- /template/nginx/lua/metrics_auth.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local SKIP_METRICS_AUTH = os.getenv("METRICS_AUTH") == "false" 4 | 5 | local function get_token() 6 | local authorization = ngx.req.get_headers()['authorization'] 7 | if type(authorization) ~= "string" then 8 | return nil 9 | end 10 | local matched = ngx.re.match(authorization, 'Bearer (.*)', 'jo') 11 | 12 | if matched == nil then 13 | return nil 14 | end 15 | local token = matched[1] 16 | if token == nil then 17 | return nil 18 | end 19 | return token 20 | end 21 | 22 | function _M.verify_auth() 23 | if SKIP_METRICS_AUTH then 24 | return 25 | end 26 | local token = get_token() 27 | if token == nil then 28 | ngx.status = 401 29 | ngx.say("Unauthorized") 30 | ngx.exit(401) 31 | end 32 | end 33 | 34 | return _M 35 | -------------------------------------------------------------------------------- /template/nginx/lua/phase/balancer_phase.lua: -------------------------------------------------------------------------------- 1 | local balancer = require("balancer.balance") 2 | balancer.balance() 3 | -------------------------------------------------------------------------------- /template/nginx/lua/phase/l7_header_filter_phase.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local e = require "error" 3 | local str = require "resty.string" 4 | local pm = require("plugins.core.plugin_manager") 5 | 6 | local matched_policy = ngx.ctx.matched_policy 7 | if matched_policy == nil then 8 | return 9 | end 10 | local cors = require "cors" 11 | local rewrite_header = require "rewrite_header" 12 | 13 | cors.header_filter() 14 | rewrite_header.rewrite_response_header() 15 | if ngx.ctx.is_alb_err then 16 | return 17 | end 18 | 19 | if ngx.ctx.alb_ctx.matched_policy then 20 | pm.response_header_filter_hook(ngx.ctx.alb_ctx) 21 | end 22 | 23 | local code = str.atoi(ngx.var.status) 24 | if code >= 400 then 25 | e.http_backend_error(code, "read " .. tostring(ngx.var.upstream_bytes_received) .. " byte data from backend") 26 | end 27 | -------------------------------------------------------------------------------- /template/nginx/lua/phase/log_phase.lua: -------------------------------------------------------------------------------- 1 | -- format:on style:emmy 2 | 3 | local metrics = require("metrics") 4 | local pm = require("plugins.core.plugin_manager") 5 | 6 | -- request may jump to log phase directly (such like jumped via modsecurity) 7 | if not ngx.ctx.alb_ctx then 8 | return 9 | end 10 | metrics.log() 11 | if ngx.ctx.alb_ctx.matched_policy then 12 | pm.log_hook(ngx.ctx.alb_ctx) 13 | end 14 | -------------------------------------------------------------------------------- /template/nginx/lua/phase/ssl_cert_phase.lua: -------------------------------------------------------------------------------- 1 | local c = require "cert_tool" 2 | c.select_cert() 3 | -------------------------------------------------------------------------------- /template/nginx/lua/plugins/auth/auth.lua: -------------------------------------------------------------------------------- 1 | -- format:on style:emmy 2 | 3 | local cache = require("config.cache") 4 | local eh = require("error") 5 | local forward_auth = require("plugins.auth.forward_auth") 6 | local basic_auth = require("plugins.auth.basic_auth") 7 | 8 | local _m = { 9 | } 10 | 11 | ---@class AuthCtx 12 | ---@field auth_cookie? table the cookie from auth response 13 | ---@field always_set_cookie boolean 14 | 15 | ---@param ctx AlbCtx 16 | function _m.after_rule_match_hook(ctx) 17 | local auth_cfg, err = _m.get_config(ctx) 18 | if err ~= nil then 19 | eh.exit("get auth config fail", err) 20 | return 21 | end 22 | if auth_cfg == nil then 23 | return 24 | end 25 | forward_auth.do_forward_auth_if_need(auth_cfg, ctx) 26 | basic_auth.do_basic_auth_if_need(auth_cfg, ctx) 27 | end 28 | 29 | ---@param ctx AlbCtx 30 | function _m.response_header_filter_hook(ctx) 31 | if ctx.auth == nil then 32 | return 33 | end 34 | forward_auth.add_cookie_if_need(ctx) 35 | end 36 | 37 | ---@param ctx AlbCtx 38 | ---@return AuthPolicy? 39 | ---@return any? error 40 | function _m.get_config(ctx) 41 | return cache.get_config_from_policy(ctx.matched_policy, "auth") 42 | end 43 | 44 | return _m 45 | -------------------------------------------------------------------------------- /template/nginx/lua/plugins/auth/buffer_md5.lua: -------------------------------------------------------------------------------- 1 | local ffi = require "ffi" 2 | 3 | local C = ffi.C 4 | local ffi_new = ffi.new 5 | local ffi_string = ffi.string 6 | local ngx = ngx 7 | local subsystem = ngx.config.subsystem 8 | 9 | 10 | local ngx_lua_ffi_md5_bin 11 | if subsystem == "http" then 12 | ffi.cdef [[ 13 | void ngx_http_lua_ffi_md5_bin(const unsigned char *src, size_t len, 14 | unsigned char *dst); 15 | ]] 16 | ngx_lua_ffi_md5_bin = C.ngx_http_lua_ffi_md5_bin 17 | end 18 | 19 | local MD5_DIGEST_LEN = 16 20 | local md5_buf = ffi_new("unsigned char[?]", MD5_DIGEST_LEN) 21 | 22 | local _m = {} 23 | 24 | -- 17ms -> 14ms 25 | _m.md5_bin = function (sb) 26 | local ptr, len = sb:ref() 27 | ngx_lua_ffi_md5_bin(ptr, len, md5_buf) 28 | return ffi_string(md5_buf, MD5_DIGEST_LEN) 29 | end 30 | 31 | return _m 32 | -------------------------------------------------------------------------------- /template/nginx/lua/plugins/otel/tool.lua: -------------------------------------------------------------------------------- 1 | local attr = require("opentelemetry.attribute") 2 | 3 | local _M = {} 4 | ---insert string attribute to table if val is not nil 5 | ---@param m table 6 | ---@param key string 7 | ---@param val? string 8 | function _M.attribute_set_string(m, key, val) 9 | if val == nil then 10 | return 11 | end 12 | table.insert(m, attr.string(key, val)) 13 | end 14 | 15 | return _M 16 | -------------------------------------------------------------------------------- /template/nginx/lua/plugins/timeout.lua: -------------------------------------------------------------------------------- 1 | local _m = {} 2 | local cache = require("config.cache") 3 | local json = require "cjson" 4 | local eh = require("error") 5 | local ngx_balancer = require "ngx.balancer" 6 | 7 | --- milliseconds to seconds,if ms is nil return nil 8 | --- @param ms number|nil 9 | ---@return number|nil 10 | local function ms2sec(ms) 11 | if ms == nil or ms == json.null then 12 | return nil 13 | end 14 | if ms <= 0 then 15 | return nil 16 | end 17 | return ms / 1000 18 | end 19 | 20 | ---@param ctx AlbCtx 21 | function _m.balancer_hook(ctx) 22 | local timeout_cfg, err = _m.get_config(ctx) 23 | if err ~= nil or timeout_cfg == nil then 24 | return 25 | end 26 | 27 | local connect = ms2sec(timeout_cfg.proxy_connect_timeout_ms) 28 | local send = ms2sec(timeout_cfg.proxy_send_timeout_ms) 29 | local read = ms2sec(timeout_cfg.proxy_read_timeout_ms) 30 | -- ngx.log(ngx.ERR, "[debug] set timeout ", connect, " ", send, " ", read) 31 | local _, err = ngx_balancer.set_timeouts(connect, send, read) 32 | if err ~= nil then 33 | eh.exit("set timeout fail", err) 34 | end 35 | end 36 | 37 | ---@param ctx AlbCtx 38 | ---@return TimeoutCr? 39 | ---@return any? error 40 | function _m.get_config(ctx) 41 | return cache.get_config_from_policy(ctx.matched_policy, "timeout") 42 | end 43 | 44 | return _m 45 | -------------------------------------------------------------------------------- /template/nginx/lua/replace_prefix_match.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | -- return the new url 4 | local sub = string.sub 5 | function _M.replace(url, prefix_match, replace_prefix) 6 | if sub(url, 1, #prefix_match) ~= prefix_match then 7 | -- ngx.log(ngx.ERR, "not match " .. url .. " " .. prefix_match) 8 | return url 9 | end 10 | 11 | local left = sub(url, #prefix_match + 1, #url) 12 | local prefix = replace_prefix 13 | local prefix_endwith_slash = sub(prefix, -1) == "/" 14 | local left_startwith_slash = sub(left, 1, 1) == "/" 15 | 16 | local sep = "/" 17 | if prefix_endwith_slash and left_startwith_slash then 18 | prefix = sub(prefix, 1, #prefix - 1) 19 | sep = "" 20 | end 21 | if prefix_endwith_slash or left_startwith_slash then 22 | sep = "" 23 | end 24 | if left == "" then 25 | sep = "" 26 | end 27 | 28 | -- ngx.log(ngx.ERR, "xx " .. prefix .. " | " .. sep .. " | " .. left) 29 | -- ngx.log(ngx.ERR, "xx " .. tostring(prefix_endwith_slash) .. " " .. tostring(left_startwith_slash)) 30 | local new_url = prefix .. sep .. left 31 | if new_url == "" then 32 | return "/" 33 | end 34 | return new_url 35 | end 36 | return _M 37 | -------------------------------------------------------------------------------- /template/nginx/lua/types/common.lua: -------------------------------------------------------------------------------- 1 | ---@alias var_string string a string may contain nginx variable 2 | -------------------------------------------------------------------------------- /template/nginx/lua/types/vendor.lua: -------------------------------------------------------------------------------- 1 | ---@meta 2 | ---@class Tracer 3 | local Tracer = {} 4 | 5 | ---comment 6 | ---@param context any 7 | ---@param name string 8 | ---@param config any 9 | function Tracer:start(context, name, config) end 10 | 11 | local _ = Tracer 12 | -------------------------------------------------------------------------------- /template/nginx/lua/utils/compress.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable: different-requires 2 | local _M = {} 3 | local zlib = require('lua-ffi-zlib.lib.ffi-zlib') 4 | -- decompress zlib format data from file 5 | -- arg fpath: string, path of the file 6 | -- ret out: string|nil,err: string| nil 7 | local _decompress_from_file = function(fpath) 8 | local f = io.open(fpath, "rb") 9 | if f == nil then 10 | return nil, "decompress file is nill" 11 | end 12 | local input = function(bufsize) 13 | local d = f:read(bufsize) 14 | if d == nil then 15 | return nil 16 | end 17 | return d 18 | end 19 | local out = {} 20 | local output = function(data) 21 | table.insert(out, data) 22 | end 23 | local ok, err = zlib.inflateGzip(input, output) 24 | if not ok then 25 | return nil,err 26 | end 27 | return table.concat(out),nil 28 | end 29 | 30 | -- decompress zlib format data from file 31 | -- arg fpath: string, path of the file 32 | -- ret out: string|nil,err: string| nil 33 | function _M.decompress_from_file(fpath) 34 | local ok,out,err = pcall(_decompress_from_file,fpath) 35 | if not ok then 36 | return nil,"decompress fail "..out 37 | end 38 | if err ~= nil then 39 | return nil,"decompress fail "..err 40 | end 41 | return out,nil 42 | end 43 | 44 | return _M -------------------------------------------------------------------------------- /template/nginx/lua/utils/generic_ext.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | 4 | --- nil_or return second if first is nil or empty string. 5 | -- @return string 6 | function _M.nil_or(first, second,empty) 7 | if first == nil then 8 | return second 9 | end 10 | if first == empty then 11 | return second 12 | end 13 | return first 14 | end 15 | 16 | return _M -------------------------------------------------------------------------------- /template/nginx/lua/utils/numer_ext.lua: -------------------------------------------------------------------------------- 1 | local g_ext = require "utils.generic_ext" 2 | 3 | local _M = {} 4 | 5 | --- nil_or return second if first is nil or empty string. 6 | -- @return string 7 | function _M.nil_or(first, second) 8 | return g_ext.nil_or(first, second, 0) 9 | end 10 | 11 | return _M 12 | -------------------------------------------------------------------------------- /template/nginx/lua/utils/subsystem.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local _M = {} 3 | 4 | local ngx_config = ngx.config 5 | 6 | local current_subsystem = ngx_config.subsystem 7 | 8 | local HTTP_SUBSYSTEM = "http" 9 | local STREAM_SUBSYSTEM = "stream" 10 | 11 | _M.CURRENT_SYBSYSTEM = current_subsystem 12 | _M.HTTP_SUBSYSTEM = HTTP_SUBSYSTEM 13 | _M.STREAM_SUBSYSTEM = STREAM_SUBSYSTEM 14 | 15 | ---@return boolean 16 | function _M.is_http_subsystem() 17 | return current_subsystem == HTTP_SUBSYSTEM 18 | end 19 | 20 | ---@return boolean 21 | function _M.is_stream_subsystem() 22 | return current_subsystem == STREAM_SUBSYSTEM 23 | end 24 | 25 | return _M 26 | -------------------------------------------------------------------------------- /template/nginx/lua/vendor/lua-ffi-zlib/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Hamish Forbes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /template/nginx/lua/vendor/lua-ffi-zlib/dist.ini: -------------------------------------------------------------------------------- 1 | name=lua-ffi-zlib 2 | abstract=Luajit FFI binding for zlib 3 | author=Hamish Forbes 4 | is_original=yes 5 | license=mit 6 | lib_dir=lib 7 | repo_link=https://github.com/hamishforbes/lua-ffi-zlib 8 | main_module=lib/ffi-zlib.lua 9 | requires = luajit 10 | -------------------------------------------------------------------------------- /template/nginx/lua/vendor/lua-ffi-zlib/lua-ffi-zlib-0.4-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-ffi-zlib" 2 | version = "0.4-0" 3 | source = { 4 | url = "git://github.com/hamishforbes/lua-ffi-zlib", 5 | tag = "v0.4" 6 | } 7 | description = { 8 | summary = "A Lua module using LuaJIT's FFI feature to access zlib.", 9 | homepage = "https://github.com/hamishforbes/lua-ffi-zlib", 10 | maintainer = "Hamish Forbes" 11 | } 12 | dependencies = { 13 | "lua >= 5.1", 14 | } 15 | build = { 16 | type = "builtin", 17 | modules = { 18 | ["ffi-zlib"] = "lib/ffi-zlib.lua", 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /template/nginx/lua/vendor/lua-ffi-zlib/lua-ffi-zlib-0.5-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-ffi-zlib" 2 | version = "0.5-0" 3 | source = { 4 | url = "git://github.com/hamishforbes/lua-ffi-zlib", 5 | tag = "v0.5" 6 | } 7 | description = { 8 | summary = "A Lua module using LuaJIT's FFI feature to access zlib.", 9 | homepage = "https://github.com/hamishforbes/lua-ffi-zlib", 10 | maintainer = "Hamish Forbes" 11 | } 12 | dependencies = { 13 | "lua >= 5.1", 14 | } 15 | build = { 16 | type = "builtin", 17 | modules = { 18 | ["ffi-zlib"] = "lib/ffi-zlib.lua", 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /template/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | # a mini nginx.conf 2 | worker_processes 1; 3 | 4 | pid /etc/alb2/nginx/nginx.pid; 5 | error_log stderr notice; 6 | 7 | events { 8 | multi_accept on; 9 | worker_connections 51200; 10 | } 11 | 12 | http {} 13 | -------------------------------------------------------------------------------- /template/nginx/policy.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "certificate_map": { 3 | "443": { 4 | "key": "", 5 | "cert": "" 6 | }, 7 | "a.b.com": { 8 | "key": "", 9 | "cert": "" 10 | } 11 | }, 12 | "stream": { 13 | "tcp": { 14 | "80": { 15 | "rule": "rule1", 16 | "upstream": "u1" 17 | } 18 | }, 19 | "udp": { 20 | "80": { 21 | "rule": "rule2", 22 | "upstream": "u2" 23 | } 24 | } 25 | }, 26 | "http": { 27 | "tcp": { 28 | "81": { 29 | "rule": "rule2", 30 | "upstream": "u2" 31 | } 32 | } 33 | }, 34 | "backend_group": [ 35 | { 36 | "name": "u1", 37 | "backends": [ 38 | { 39 | "address": "127.0.0.1", 40 | "port": 9999, 41 | "weight": 100 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "u2", 47 | "backends": [ 48 | { 49 | "address": "127.0.0.1", 50 | "port": 9999, 51 | "weight": 100 52 | } 53 | ] 54 | }, 55 | { 56 | "name": "u3", 57 | "backends": [ 58 | { 59 | "address": "127.0.0.1", 60 | "port": 9999, 61 | "weight": 100 62 | } 63 | ] 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /template/nginx/run-nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -n "$TAIL_MODE" ]; then 4 | echo "tail mode wait forever" 5 | tail -f /dev/null 6 | fi 7 | 8 | umask 027 9 | mkdir -p /alb/nginx/run 10 | openssl dhparam -dsaparam -out /etc/alb2/nginx/dhparam.pem 2048 11 | cfg_path=$OLD_CONFIG_PATH 12 | if [ ! -f $cfg_path ]; then 13 | echo "copy init nginx.conf" 14 | cp /alb/nginx/nginx.conf $cfg_path 15 | cat $cfg_path 16 | fi 17 | 18 | nginx -g "daemon off;" -c /etc/alb2/nginx/nginx.conf -e /dev/stderr -p /alb/nginx/run 19 | -------------------------------------------------------------------------------- /template/t/cors.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | our $policy = <<'_EOC_'; 8 | { 9 | "certificate_map": {}, 10 | "http": {"tcp": {"80": [ 11 | { 12 | "rule": "", 13 | "internal_dsl": [ 14 | [ 15 | "STARTS_WITH", 16 | "URL", 17 | "/t" 18 | ] 19 | ], 20 | "enable_cors": true, 21 | "upstream": "test-upstream-1" 22 | }] } 23 | }, 24 | "backend_group": [ 25 | { 26 | "name": "test-upstream-1", 27 | "mode": "http", 28 | "backends": [ 29 | { 30 | "address": "127.0.0.1", 31 | "port": 9999, 32 | "weight": 100 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | _EOC_ 39 | 40 | log_level("info"); 41 | no_shuffle(); 42 | no_root_location(); 43 | run_tests(); 44 | 45 | __DATA__ 46 | 47 | === TEST 1: http cors 48 | --- policy eval: $::policy 49 | --- lua_test 50 | local F = require("F");local u = require("util");local h = require("test-helper"); 51 | local httpc = require("resty.http").new() 52 | local res, err = httpc:request_uri("http://127.0.0.1:80/t",{method="OPTIONS"}) 53 | u.log(F"{u.inspect(res)}") 54 | h.assert_eq(res.status,204) 55 | h.assert_eq(res.headers["Access-Control-Allow-Origin"],"*") -------------------------------------------------------------------------------- /template/t/e2e/auth_test/auth_test.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | my $ALB_BASE = $ENV{'TEST_BASE'}; 8 | 9 | our $tt = t::Alauda::get_test_name(__FILE__); 10 | 11 | log_level("info"); 12 | master_process_enabled("on"); 13 | no_shuffle(); 14 | no_root_location(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: auth 20 | --- mock_backend eval: "1880 $::tt" 21 | --- lua_test_eval eval: "require('$::tt').test()" 22 | -------------------------------------------------------------------------------- /template/t/e2e/cert/cert.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | my $base = $ENV{'TEST_BASE'}; 8 | our $cert = <<_EOC_; 9 | $base/cert/tls.crt $base/cert/tls.key 10 | _EOC_ 11 | 12 | our $http_config = <<_EOC_; 13 | server { 14 | listen 1880; 15 | location / { 16 | content_by_lua_block { 17 | require("e2e.cert.cert").as_backend(1880) 18 | } 19 | } 20 | } 21 | _EOC_ 22 | 23 | 24 | log_level("info"); 25 | workers(4); 26 | master_process_enabled("on"); 27 | no_shuffle(); 28 | no_root_location(); 29 | run_tests(); 30 | 31 | __DATA__ 32 | 33 | === TEST 1: cert test 34 | --- certificate eval: $::cert 35 | --- http_config eval: $::http_config 36 | --- alb_https_port: 8443,9443 37 | --- disable_init_worker 38 | --- init_worker_eval: require("mock_worker_init").init_worker() 39 | --- timeout: 9999999 40 | --- lua_test_eval: require("e2e.cert.cert").test() 41 | -------------------------------------------------------------------------------- /template/t/e2e/error_page/error.t: -------------------------------------------------------------------------------- 1 | use t::Alauda; 2 | use Test::Nginx::Socket 'no_plan'; 3 | use Test::Nginx::Socket; 4 | 5 | our $http_config = <<_EOC_; 6 | server { 7 | listen 1880; 8 | location / { 9 | content_by_lua_block { 10 | require("e2e.error_page.error").as_backend(1880) 11 | } 12 | } 13 | } 14 | _EOC_ 15 | 16 | 17 | log_level("info"); 18 | master_process_enabled("on"); 19 | no_shuffle(); 20 | no_root_location(); 21 | run_tests(); 22 | 23 | __DATA__ 24 | 25 | === TEST 1: error page test 26 | --- http_config eval: $::http_config 27 | --- timeout: 9999999 28 | --- lua_test_eval: require("e2e.error_page.error").test() 29 | -------------------------------------------------------------------------------- /template/t/e2e/metrics/metrics.t: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | use warnings; 4 | use t::Alauda; 5 | use Test::Nginx::Socket 'no_plan'; 6 | use Test::Nginx::Socket; 7 | 8 | log_level("info"); 9 | master_process_enabled("on"); 10 | no_shuffle(); 11 | # workers(4); # test for mutli metrics # currently mock init_worker has no way to sync backend in each worker.. 12 | no_root_location(); 13 | run_tests(); 14 | 15 | __DATA__ 16 | 17 | === TEST 1: clean-metrics 18 | --- mock_backend: 1880 e2e.metrics.metrics 19 | --- timeout: 9999999 20 | --- lua_test_eval: require("e2e.metrics.metrics").test() 21 | -------------------------------------------------------------------------------- /template/t/e2e/ping/ping.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local _M = {} 3 | local h = require "test-helper" 4 | local u = require "util" 5 | local ph = require("policy_helper") 6 | 7 | function _M.as_backend() 8 | ngx.say "ok" 9 | end 10 | 11 | function _M.test() 12 | -- LuaFormatter off 13 | ph.set_policy_lua({ 14 | http = {tcp = {["80"] = { 15 | {rule = "1", internal_dsl = {{"STARTS_WITH", "URL", "/t1"}}, upstream = "test-upstream-1"}}} 16 | }, 17 | backend_group = { 18 | {name = "test-upstream-1", mode = "http", backends = {{address = "127.0.0.1", port = 1880, weight = 100}}} 19 | } } 20 | ) 21 | -- LuaFormatter on 22 | local res = h.assert_curl("http://127.0.0.1:80/t1") 23 | u.logs(res) 24 | h.assert_eq(res.body, "ok\n") 25 | end 26 | 27 | return _M 28 | -------------------------------------------------------------------------------- /template/t/e2e/ping/ping.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | log_level("info"); 8 | master_process_enabled("on"); 9 | no_shuffle(); 10 | no_root_location(); 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: ping 16 | --- mock_backend: 1880 e2e.ping.ping 17 | --- timeout: 9999999 18 | --- lua_test_eval: require("e2e.ping.ping").test() 19 | -------------------------------------------------------------------------------- /template/t/e2e/retry_test/retry_test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | local F = require("F"); 3 | local u = require("util"); 4 | local h = require("test-helper"); 5 | local httpc = require("resty.http").new(); 6 | 7 | local function get_string_count(msg, module) 8 | local map = { 9 | ["http"] = "./template/servroot/logs/error.log", 10 | ["stream"] = "./template/servroot/logs/error.log", 11 | } 12 | local cmd = string.format([[bash -c "cat %s |grep '%s' | wc -l"]], map[module], msg) 13 | local final, err = u.shell(cmd) 14 | if err ~= nil and err ~= "" then 15 | h.fail("get string count fail") 16 | end 17 | return tonumber(final) 18 | end 19 | 20 | function _M.test() 21 | local msg = "connect() failed (111: Connection refused)" 22 | do 23 | local origin = get_string_count(msg, "http") 24 | local res, err = httpc:request_uri("http://127.0.0.1/ping") 25 | h.assert_eq(res.status, 502) 26 | local final = get_string_count(msg, "http") 27 | h.assert_eq(final - origin, 5, F("http {origin} {final}")) 28 | end 29 | do 30 | local origin = get_string_count(msg, "stream") 31 | local res, err = httpc:request_uri("http://127.0.0.1:81/ping") 32 | h.assert_eq(err, "connection reset by peer") 33 | local final = get_string_count(msg, "stream") 34 | h.assert_eq(final - origin, 5, F "stream {origin} {final}") 35 | end 36 | end 37 | 38 | return _M 39 | -------------------------------------------------------------------------------- /template/t/e2e/rewrite_request/test.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | log_level("info"); 8 | master_process_enabled("on"); 9 | no_shuffle(); 10 | no_root_location(); 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: ping 16 | --- mock_backend: 1880 e2e.rewrite_request.test 17 | --- disable_init_worker 18 | --- init_worker_eval: require("mock_worker_init").init_worker() 19 | --- timeout: 9999999 20 | --- lua_test_eval: require("e2e.rewrite_request.test").test() 21 | -------------------------------------------------------------------------------- /template/t/e2e/rule_match/rule.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local _M = {} 3 | local h = require "test-helper" 4 | local u = require "util" 5 | local ph = require("policy_helper") 6 | 7 | function _M.as_backend() 8 | ngx.say "ok" 9 | end 10 | 11 | function _M.test() 12 | -- LuaFormatter off 13 | ph.set_policy_lua({ 14 | http = { 15 | tcp = { 16 | ["80"] = { 17 | { rule = "1", internal_dsl = { "AND", { "REGEX", "PARAM", "a", ".*" }, { "REGEX", "URL", "/t1.*" } }, upstream = "test-upstream-1" } } 18 | } 19 | }, 20 | backend_group = { 21 | { name = "test-upstream-1", mode = "http", backends = { { address = "127.0.0.1", port = 1880, weight = 100 } } } 22 | } 23 | } 24 | ) 25 | -- LuaFormatter on 26 | h.assert_curl("http://127.0.0.1:80/t1?v=v", {}, { status = 404 }) 27 | end 28 | 29 | return _M 30 | -------------------------------------------------------------------------------- /template/t/e2e/rule_match/rule.t: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | use warnings; 4 | use t::Alauda; 5 | use Test::Nginx::Socket 'no_plan'; 6 | use Test::Nginx::Socket; 7 | 8 | our $tt = t::Alauda::get_test_name(__FILE__); 9 | 10 | log_level("info"); 11 | master_process_enabled("on"); 12 | workers(1); 13 | worker_connections(51200); 14 | no_shuffle(); 15 | no_root_location(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: rule matches 21 | --- timeout: 30 22 | --- mock_backend eval: "1880 $::tt" 23 | --- init_worker_eval: require("mock_worker_init").init_worker() 24 | --- lua_test_eval eval: "require('$::tt').test()" 25 | -------------------------------------------------------------------------------- /template/t/e2e/timeout_test/timeout_test.t: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | use warnings; 4 | use t::Alauda; 5 | use Test::Nginx::Socket 'no_plan'; 6 | use Test::Nginx::Socket; 7 | 8 | my $ALB_BASE = $ENV{'TEST_BASE'}; 9 | 10 | our $tt = t::Alauda::get_test_name(__FILE__); 11 | 12 | log_level("info"); 13 | master_process_enabled("on"); 14 | no_shuffle(); 15 | no_root_location(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: timeout 21 | --- mock_backend eval: "1880 $::tt" 22 | --- lua_test_eval eval: "require('$::tt').test()" 23 | 24 | === TEST 2: timeout tcp 25 | --- mock_backend eval: "1880 $::tt" 26 | --- lua_test_stream_mode: "true" 27 | --- lua_test_eval eval: "require('$::tt').test()" 28 | -------------------------------------------------------------------------------- /template/t/e2e/trace/trace.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | 8 | our $http_config = <<_EOC_; 9 | server { 10 | listen 1880; 11 | location / { 12 | content_by_lua_block { 13 | require("e2e.trace.trace").as_backend(1880) 14 | } 15 | } 16 | } 17 | _EOC_ 18 | 19 | 20 | log_level("info"); 21 | master_process_enabled("on"); 22 | no_shuffle(); 23 | no_root_location(); 24 | run_tests(); 25 | 26 | __DATA__ 27 | 28 | === TEST 1: trace test 29 | --- http_config eval: $::http_config 30 | --- timeout: 9999999 31 | --- lua_test_eval: require("e2e.trace.trace").test() 32 | -------------------------------------------------------------------------------- /template/t/lib/mock_worker_init.lua: -------------------------------------------------------------------------------- 1 | -- format:on 2 | local M = {} 3 | 4 | local balancer = require("balancer.balance") 5 | local ph = require("config.policy_fetch") 6 | local cache = require("config.cache") 7 | local u = require("util") 8 | local subsys = require "utils.subsystem" 9 | local shm = require "config.shmap" 10 | 11 | function M.init_worker(_cfg) 12 | ngx.update_time() 13 | u.log("life: init worker " .. tostring(ngx.worker.id())) 14 | if subsys.is_http_subsystem() then 15 | cache.init_l7() 16 | else 17 | cache.init_l4() 18 | end 19 | local policy_raw, err = u.file_read_to_string(os.getenv("TEST_BASE") .. "/policy.new") 20 | if err ~= nil then 21 | ngx.exit(0) 22 | end 23 | ngx.update_time() 24 | shm.set_policy_raw("{}") 25 | ngx.update_time() 26 | ph.update_policy(policy_raw, "manual") 27 | ngx.update_time() 28 | u.log "life: update policy ok" 29 | balancer.sync_backends() 30 | ngx.update_time() 31 | u.log "life: sync backend ok" 32 | if subsys.is_http_subsystem() then 33 | ngx.update_time() 34 | require("metrics").init() 35 | ngx.update_time() 36 | u.log "life: init metrics ok" 37 | end 38 | end 39 | 40 | return M 41 | -------------------------------------------------------------------------------- /template/t/lib/policy_helper.lua: -------------------------------------------------------------------------------- 1 | local common = require "utils.common" 2 | local p = require "config.policy_fetch" 3 | local balancer = require("balancer.balance") 4 | local M = {} 5 | 6 | function M.set_policy_json_str(policy) 7 | p.update_policy(policy, "manual") 8 | ngx.sleep(1) 9 | -- TODO it will only update cache for the current worker.. 10 | balancer.sync_backends() 11 | end 12 | 13 | function M.set_policy_lua(policy_table) 14 | M.set_policy_json_str(common.json_encode(policy_table, true)) 15 | end 16 | 17 | return M 18 | -------------------------------------------------------------------------------- /template/t/manually/fortio/fortio.perf: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | 8 | our $perf_case = "require(\"perf.e2e.fortio\").test(\"$ENV{PERF_CASE}\",\"$ENV{PERF_TIME}\")"; 9 | our $perf_time = "$ENV{PERF_TIME}"; 10 | warn "perf_case: $perf_case\n perf_time: $perf_time\n"; 11 | 12 | log_level("info"); 13 | master_process_enabled("on"); 14 | workers(1); 15 | worker_connections(51200); 16 | no_shuffle(); 17 | no_root_location(); 18 | run_tests(); 19 | 20 | __DATA__ 21 | 22 | === TEST 1: perf 23 | --- init_worker_eval: require("mock_worker_init").init_worker() 24 | --- timeout eval: $::perf_time 25 | --- lua_test_eval eval: $::perf_case 26 | -------------------------------------------------------------------------------- /template/t/manually/nyi/nyi: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | our $tt = t::Alauda::get_test_name(__FILE__); 8 | 9 | log_level("info"); 10 | master_process_enabled("on"); 11 | workers(1); 12 | worker_connections(51200); 13 | no_shuffle(); 14 | no_root_location(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: nyi 20 | --- timeout: 30 21 | --- enable_nyi 22 | --- init_worker_eval: require("mock_worker_init").init_worker() 23 | --- lua_test_eval eval: "require('$::tt').test()" 24 | -------------------------------------------------------------------------------- /template/t/manually/nyi/nyi.lua: -------------------------------------------------------------------------------- 1 | local ph = require "policy_helper" 2 | local u = require "util" 3 | local h = require "test-helper" 4 | local _M = {} 5 | 6 | local function get_nyi_log() 7 | local cmd = string.format([[bash -c "cat %s |grep 'NYI' " ]], "./template/.nyi.log") 8 | local out, err = u.shell(cmd) 9 | if err ~= nil and err ~= "" then 10 | h.fail("get nyi log fail " .. err) 11 | end 12 | return out 13 | end 14 | function _M.test() 15 | ph.set_policy_lua({ 16 | http = { 17 | tcp = { 18 | ["80"] = { 19 | { rule = "fortio", internal_dsl = { { "STARTS_WITH", "URL", "/" } }, upstream = "fortio" }, 20 | } 21 | } 22 | }, 23 | backend_group = { 24 | { name = "fortio", mode = "http", backends = { { address = "127.0.0.1", port = 8080, weight = 100 } } } 25 | }, 26 | }) 27 | u.logs("hello") 28 | local time = "30s" 29 | local cmd = 30 | "fortio load -a -labels 'u:nyi' -logger-force-color -c 8 -qps 30000 -nocatchup -uniform -t " .. 31 | time .. " 'http://127.0.0.1:80?size=1024:99'" 32 | local out, err = u.shell(cmd) 33 | u.logs("out", out, "err", err) 34 | u.log(get_nyi_log()) 35 | end 36 | 37 | return _M 38 | -------------------------------------------------------------------------------- /template/t/manually/otel_test/otel_test: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | our $tt = t::Alauda::get_test_name(__FILE__); 8 | 9 | log_level("info"); 10 | master_process_enabled("on"); 11 | workers(1); 12 | worker_connections(51200); 13 | no_shuffle(); 14 | no_root_location(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: otel 20 | --- mock_backend eval: "1880 $::tt" 21 | --- timeout: 999999 22 | --- init_worker_eval: require("mock_worker_init").init_worker() 23 | --- lua_test_eval eval: "require('$::tt').test()" 24 | -------------------------------------------------------------------------------- /template/t/nignx_config.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | 6 | no_shuffle(); 7 | no_root_location(); 8 | run_tests(); 9 | 10 | __DATA__ 11 | 12 | === TEST 1: valid nginx config ok 13 | --- log_level: info 14 | --- alb_stream_server_config 15 | server { 16 | listen 9002 so_keepalive=on; 17 | content_by_lua_block { 18 | ngx.print("ok"); 19 | } 20 | } 21 | server { 22 | listen 9001 so_keepalive=30m::10; 23 | content_by_lua_block { 24 | ngx.print("ok"); 25 | } 26 | } 27 | server { 28 | listen 9003 so_keepalive=30m:1s:10; 29 | content_by_lua_block { 30 | ngx.print("ok"); 31 | } 32 | } 33 | --- lua_test 34 | ngx.log(ngx.INFO, "ok") 35 | -------------------------------------------------------------------------------- /template/t/resource/policy.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/template/t/resource/policy.bin -------------------------------------------------------------------------------- /template/t/resource/policy.bin.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/template/t/resource/policy.bin.empty -------------------------------------------------------------------------------- /template/t/resource/policy.bin.invalid: -------------------------------------------------------------------------------- 1 | invalid -------------------------------------------------------------------------------- /template/t/unit/common_test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local t = require("test-helper"); 4 | local u = require("util"); 5 | local c = require("utils.common") 6 | 7 | function _M.test() 8 | u.logs("in common test") 9 | u.logs(c.json_decode('{"a":null}')) 10 | end 11 | 12 | return _M 13 | -------------------------------------------------------------------------------- /template/t/unit/cors_test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local h = require("test-helper"); 4 | local cors = require("cors") 5 | 6 | function _M.test() 7 | h.assert_true(cors.origin_contains("http://a.com,http://b.com", "http://a.com")) 8 | h.assert_true(cors.origin_contains("http://a.com,http://b.com", "http://b.com")) 9 | h.assert_true(cors.origin_contains("http://a.com,http://b.com:123", "http://b.com:123")) 10 | h.assert_true(not cors.origin_contains("http://a.com:80,http://b.com:123", "http://a.com")) 11 | h.assert_true(not cors.origin_contains("http://a.com.cn,http://b.com", "http://a.com")) 12 | end 13 | 14 | return _M 15 | -------------------------------------------------------------------------------- /template/t/unit/replace_prefix_match_test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local F = require("F"); 4 | local u = require("util") 5 | local h = require("test-helper"); 6 | local r = require("replace_prefix_match") 7 | 8 | -- return the new url 9 | function _M.test() 10 | local cases = { 11 | {"/foo/bar", "/foo", "/xyz", "/xyz/bar"}, -- 12 | {"/foo/bar", "/foo", "/xyz/", "/xyz/bar"}, -- 13 | {"/foo/bar", "/foo/", "/xyz", "/xyz/bar"}, -- 14 | {"/foo/bar", "/foo/", "/xyz/", "/xyz/bar"}, -- 15 | {"/foo", "/foo", "/xyz", "/xyz"}, -- 16 | {"/foo/", "/foo", "/xyz", "/xyz/"}, -- 17 | {"/foo/bar", "/foo", "", "/bar"}, -- 18 | {"/foo/", "/foo", "", "/"}, -- 19 | {"/foo", "/foo", "", "/"}, -- 20 | {"/foo/", "/foo", "/", "/"}, -- 21 | {"/foo", "/foo", "/", "/"} -- 22 | } 23 | local fail = false 24 | local msg = "" 25 | for k, c in pairs(cases) do 26 | h.P(F "case {k}") 27 | local url = c[1] 28 | local prefix_match = c[2] 29 | local replace_prefix = c[3] 30 | local expect_result = c[4] 31 | local result = r.replace(url, prefix_match, replace_prefix) 32 | if expect_result ~= result then 33 | h.P(F "fail {k} e {expect_result} r {result} " .. u.inspect(c)) 34 | fail = true 35 | break 36 | end 37 | end 38 | if fail then 39 | h.P("fail ") 40 | h.fail() 41 | end 42 | end 43 | return _M 44 | -------------------------------------------------------------------------------- /template/t/unit/unit_test.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local u = require "util" 4 | local h = require("test-helper"); 5 | 6 | function _M.test() 7 | u.logs("in unit test") 8 | local run_only = os.getenv("ALB_LUA_UNIT_TEST_CASE") 9 | if run_only and run_only ~= "" then 10 | u.logs("run only", run_only) 11 | require(run_only).test() 12 | return 13 | end 14 | require("unit.replace_prefix_match_test").test() 15 | require("unit.cert_test").test() 16 | require("unit.cors_test").test() 17 | require("unit.common_test").test() 18 | require("unit.plugins.auth.auth_unit_test").test() 19 | end 20 | 21 | return _M 22 | -------------------------------------------------------------------------------- /template/t/unit/unit_test.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use t::Alauda; 4 | use Test::Nginx::Socket 'no_plan'; 5 | use Test::Nginx::Socket; 6 | 7 | 8 | log_level("info"); 9 | no_shuffle(); 10 | no_root_location(); 11 | run_tests(); 12 | 13 | 14 | __DATA__ 15 | 16 | === TEST 1: unit tests 17 | --- http_config eval: "" 18 | --- disable_init_worker 19 | --- lua_test_eval: require("unit.unit_test").test() 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | 现在alb的代码中有三重测试方式 2 | ## unit test 3 | 测试代码放在源代码相同的package 4 | 一般用于测具体的函数. 5 | ## env test 6 | 测试代码放在test/e2e下,和unit test的区别是,env test使用会启动envtest并直接启动一个alb或者operator. 7 | 一般用于测alb和operator的行为 8 | ## kind test 9 | 测试代码放在test/kind下,和env test的区别是,kind test会使用kind部署一个k8s集群,并部署operator. 10 | 一般用于测试nginx相关的逻辑,和operator部署相关的逻辑. 11 | -------------------------------------------------------------------------------- /test/alauda/README.md: -------------------------------------------------------------------------------- 1 | tests which hash testlink id and will generate allure report. 2 | which will do test in acp env. -------------------------------------------------------------------------------- /test/checklist/hr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: app.alauda.io/v1 2 | kind: HelmRequest 3 | metadata: 4 | annotations: 5 | cpaas.io/creator: admin 6 | generation: 1 7 | name: global-test 8 | namespace: cpaas-system 9 | spec: 10 | chart: stable/alauda-alb2 11 | clusterName: global 12 | namespace: cpaas-system 13 | values: 14 | address: 192.168.0.201 15 | displayName: "" 16 | enablePortProject: false 17 | LoadbalancerName: test 18 | nodeSelector: 19 | beta.kubernetes.io/os: linux 20 | projects: 21 | - ALL_ALL 22 | replicas: 1 23 | resources: 24 | limits: 25 | cpu: 200m 26 | memory: 256Mi 27 | requests: 28 | cpu: 200m 29 | memory: 256Mi -------------------------------------------------------------------------------- /test/checklist/suite_test.go: -------------------------------------------------------------------------------- 1 | package checklist 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestALBCheckList(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "alb checklist related test") 13 | } 14 | -------------------------------------------------------------------------------- /test/conformance/ingress-nginx/README.md: -------------------------------------------------------------------------------- 1 | 这个目录下的测试的特殊之处在于我们可以用相同的测试函数来依次测试alb和ingress-nginx的行为. 2 | -------------------------------------------------------------------------------- /test/conformance/ingress-nginx/lua_snip/app.lua: -------------------------------------------------------------------------------- 1 | local c = require("utils.common") 2 | if ngx.var.uri == "/ok" then 3 | ngx.say("ok") 4 | return 5 | end 6 | local id = ngx.var.http_id 7 | if id == nil then 8 | ngx.say("ok") 9 | return 10 | end 11 | ngx.log(ngx.INFO, "im app " .. id) 12 | local h, err = ngx.req.get_headers() 13 | if err ~= nil then 14 | ngx.log(ngx.ERR, "err: " .. tostring(err)) 15 | end 16 | for k, v in pairs(h) do 17 | ngx.log(ngx.ERR, "app " .. tostring(k) .. " : " .. tostring(v)) 18 | end 19 | if ngx.shared.state:get(id) == nil then 20 | ngx.shared.state:set(id, c.json_encode({})) 21 | end 22 | 23 | local data = c.json_decode(ngx.shared.state:get(id)) 24 | data["/"] = h 25 | ngx.shared.state:set(id, c.json_encode(data)) 26 | 27 | local data = c.json_decode(ngx.shared.state:get(id .. "-cfg")) 28 | for k, v in pairs(data.app_response_header) do 29 | ngx.header[k] = v 30 | end 31 | ngx.status = data.app_exit 32 | ngx.say(data.app_response_body) 33 | ngx.exit(data.app_exit) 34 | ngx.say("OK") 35 | -------------------------------------------------------------------------------- /test/conformance/ingress-nginx/lua_snip/auth.lua: -------------------------------------------------------------------------------- 1 | local c = require("utils.common") 2 | ngx.log(ngx.INFO, "im auth") 3 | local id = ngx.var.http_id 4 | local h, err = ngx.req.get_headers() 5 | if err ~= nil then 6 | ngx.log(ngx.ERR, "err: " .. tostring(err)) 7 | end 8 | 9 | if ngx.shared.state:get(id) == nil then 10 | local data = c.json_encode({}, true) 11 | ngx.log(ngx.ERR, "init state ", data, id) 12 | ngx.shared.state:set(id, data) 13 | end 14 | 15 | ngx.log(ngx.ERR, "state is " .. id .. " " .. tostring(ngx.shared.state:get(id))) 16 | local data = c.json_decode(ngx.shared.state:get(id)) 17 | data["/auth"] = h 18 | ngx.shared.state:set(id, c.json_encode(data)) 19 | 20 | for k, v in pairs(h) do 21 | ngx.log(ngx.ERR, "auth " .. tostring(k) .. " : " .. tostring(v)) 22 | end 23 | 24 | local cfg = c.json_decode(ngx.shared.state:get(id .. "-cfg")) 25 | for k, v in pairs(cfg.auth_response_header) do 26 | ngx.header[k] = v 27 | end 28 | 29 | ngx.log(ngx.ERR, "auth exit with " .. tostring(cfg.auth_exit)) 30 | ngx.status = cfg.auth_exit 31 | ngx.exit(cfg.auth_exit) 32 | ngx.say(cfg.auth_response_body) 33 | -------------------------------------------------------------------------------- /test/conformance/ingress-nginx/lua_snip/state.lua: -------------------------------------------------------------------------------- 1 | ngx.req.read_body() 2 | ngx.log(ngx.INFO, 3 | "im state " .. ngx.var.http_id .. " " .. tostring(ngx.var.request_method) .. " " .. tostring(ngx.req.get_body_data())) 4 | local id = ngx.var.http_id 5 | local c = require("utils.common") 6 | 7 | if ngx.shared.state:get(id) == nil then 8 | ngx.shared.state:set(id, c.json_encode({}, true)) 9 | end 10 | 11 | if ngx.var.request_method == "PUT" then 12 | ngx.shared.state:set(id .. "-cfg", ngx.req.get_body_data()) 13 | ngx.say("OK") 14 | return 15 | end 16 | if ngx.var.request_method == "GET" then 17 | local out = ngx.shared.state:get(id) or "{}" 18 | ngx.log(ngx.INFO, "state is " .. id .. " " .. tostring(out)) 19 | ngx.header["Content-Type"] = "application/json" 20 | ngx.say(out) 21 | end 22 | -------------------------------------------------------------------------------- /test/conformance/ingress-nginx/suite_test.go: -------------------------------------------------------------------------------- 1 | package ingressnginx 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | // 在兼容ingress-nginx的情况下,用户常问的问题是,在xxx配置下,ingress-nginx 会是什么行为 11 | // conformance test 应该能够给出一个快速的有力的回应。 12 | // 同时,这下面的case 也是我们的e2e测试用例 13 | func TestIngressNginx(t *testing.T) { 14 | RegisterFailHandler(Fail) 15 | RunSpecs(t, "ingress nginx related e2e") 16 | } 17 | -------------------------------------------------------------------------------- /test/e2e/framework/consts.go: -------------------------------------------------------------------------------- 1 | package framework 2 | 3 | var ( 4 | DEFAULT_V4_IP_POOL = []string{"199.168.0.1"} 5 | DEFAULT_V6_IP_POOL = []string{"2004::199:168:128:235"} 6 | ) 7 | -------------------------------------------------------------------------------- /test/e2e/framework/suite_helper.go: -------------------------------------------------------------------------------- 1 | package framework 2 | 3 | import ( 4 | "path" 5 | "runtime" 6 | 7 | . "alauda.io/alb2/utils/test_utils" 8 | "k8s.io/client-go/rest" 9 | ) 10 | 11 | func AlbBeforeSuite(cfg *rest.Config) { 12 | _, filename, _, _ := runtime.Caller(0) 13 | albBase := path.Join(path.Dir(filename), "../../../") 14 | err := InitAlbCr(albBase, cfg) 15 | GinkgoNoErr(err) 16 | GinkgoNoErr(err) 17 | } 18 | -------------------------------------------------------------------------------- /test/e2e/framework/tls.go: -------------------------------------------------------------------------------- 1 | package framework 2 | 3 | import ( 4 | "context" 5 | 6 | . "alauda.io/alb2/utils/test_utils" 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | type TlsExt struct { 12 | Kc *K8sClient 13 | Ctx context.Context 14 | } 15 | 16 | func (t *TlsExt) CreateTlsSecret(domain, name, ns string) (*corev1.Secret, error) { 17 | key, crt, err := GenCert(domain) 18 | if err != nil { 19 | return nil, err 20 | } 21 | secret, err := t.Kc.GetK8sClient().CoreV1().Secrets(ns).Create(t.Ctx, &corev1.Secret{ 22 | ObjectMeta: metav1.ObjectMeta{ 23 | Name: name, 24 | Namespace: ns, 25 | }, 26 | Data: map[string][]byte{ 27 | "tls.key": []byte(key), 28 | "tls.crt": []byte(crt), 29 | }, 30 | Type: corev1.SecretTypeTLS, 31 | }, metav1.CreateOptions{}) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return secret, nil 36 | } 37 | -------------------------------------------------------------------------------- /test/e2e/operator/README.md: -------------------------------------------------------------------------------- 1 | 这个package主要测试operator部署相关的东西 2 | 3 | matrix 4 | | gateway:| enable-shared | enable-standalone | disable| 5 | |--------|---------------|----------------------------| 6 | | network:| host | container | 7 | |--------|---------------|----------------------------| 8 | | alb: | enable | disable | 9 | 10 | 3 * 2 * 2 = 12 11 | gateway disable and alb disable is meaningless. left 11 12 | ## common used mode 13 | ### 1. global default 集群默认部署的alb 14 | gateway enable-shared 15 | network host 16 | alb enable 17 | ### 2. user deploy alb-host 用户部署的主机网络的alb 18 | gateway disable 19 | network host 20 | alb enable 21 | ### 3. user deploy alb-container 用户部署的容器网络的alb 22 | gateway disable 23 | network container 24 | alb enable 25 | ### 4. user deploy gateway 3.14之后加入的 独享型gateway 26 | gateway enable-standalone 27 | network container 28 | alb disable 29 | ### 5. user deploy gateway (with alb) 30 | gateway enable-standalone 31 | network container 32 | alb enable -------------------------------------------------------------------------------- /test/e2e/rule-perf-cpu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alauda/alb/314b8a693f1d84a3a5f561b846f7e1cef61bfb5c/test/e2e/rule-perf-cpu -------------------------------------------------------------------------------- /test/e2e/suite_test.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "testing" 5 | 6 | _ "alauda.io/alb2/test/e2e/alb" 7 | _ "alauda.io/alb2/test/e2e/cases" 8 | _ "alauda.io/alb2/test/e2e/gateway" 9 | _ "alauda.io/alb2/test/e2e/ingress" 10 | _ "alauda.io/alb2/test/e2e/operator/alb" 11 | _ "alauda.io/alb2/test/e2e/operator/gateway" 12 | _ "alauda.io/alb2/test/e2e/operator/public-cloud" 13 | _ "alauda.io/alb2/test/e2e/operator/rawk8s" 14 | _ "alauda.io/alb2/test/e2e/operator/simple" 15 | _ "alauda.io/alb2/test/e2e/perf" 16 | . "github.com/onsi/ginkgo/v2" 17 | . "github.com/onsi/gomega" 18 | ) 19 | 20 | func TestALB(t *testing.T) { 21 | RegisterFailHandler(Fail) 22 | RunSpecs(t, "alb operator related e2e") 23 | } 24 | -------------------------------------------------------------------------------- /test/kind/e2e/suite_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | 9 | _ "alauda.io/alb2/test/kind/e2e/gateway" 10 | _ "alauda.io/alb2/test/kind/e2e/operator" 11 | ) 12 | 13 | func TestAlbKindE2e(t *testing.T) { 14 | RegisterFailHandler(Fail) 15 | RunSpecs(t, "Kind e2e Suite") 16 | } 17 | -------------------------------------------------------------------------------- /test/kind/pkg/helper/alb-chart-ext_test.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "testing" 5 | 6 | "alauda.io/alb2/utils/log" 7 | . "alauda.io/alb2/utils/test_utils" 8 | "github.com/stretchr/testify/assert" 9 | "github.com/ztrue/tracerr" 10 | ) 11 | 12 | func TestChart(t *testing.T) { 13 | base := InitBase() 14 | l := log.L() 15 | { 16 | chart := "registry.alauda.cn:60080/acp/chart-alauda-alb2:v3.13.0-alpha.11" 17 | ac, err := LoadAlbChartFromUrl(base, NewHelm(base, nil, l), chart, l) 18 | tracerr.Print(err) 19 | assert.NoError(t, err) 20 | imgs, err := ac.ListImage() 21 | assert.NoError(t, err) 22 | l.Info("imgs", "img", imgs) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/kind/pkg/helper/king-gc_test.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestIsNeedGcKind(t *testing.T) { 12 | type TestCase struct { 13 | prefix string 14 | time int64 15 | need bool 16 | } 17 | now := time.Now().Unix() 18 | new2h := time.Now().Add(time.Hour * 2).Unix() 19 | old2h := time.Now().Add(time.Hour * -2).Unix() 20 | cases := []TestCase{ 21 | { 22 | prefix: "xx-ddd", 23 | time: now, 24 | need: false, 25 | }, 26 | { 27 | prefix: "xx-ddd", 28 | time: new2h, 29 | need: false, 30 | }, 31 | { 32 | prefix: "xx-ddd", 33 | time: old2h, 34 | need: true, 35 | }, 36 | } 37 | for _, c := range cases { 38 | need, _ := isNeedGC(fmt.Sprintf("%s-%d", c.prefix, c.time)) 39 | assert.Equal(t, need, c.need) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/kind/pkg/helper/qps/assert.go: -------------------------------------------------------------------------------- 1 | package qps 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type QpsSummaryAssert struct { 8 | summary []History 9 | } 10 | 11 | func NewSummaryAssert(sum []History) *QpsSummaryAssert { 12 | return &QpsSummaryAssert{summary: sum} 13 | } 14 | 15 | func (s *QpsSummaryAssert) NoError() { 16 | for _, s := range s.summary { 17 | for _, r := range s.records { 18 | if r.code != 200 { 19 | panic(fmt.Errorf("find a err %v", r)) 20 | } 21 | } 22 | } 23 | } 24 | 25 | func (s *QpsSummaryAssert) QpsAbove(qps int) { 26 | for _, s := range s.summary { 27 | // qps := s.success / uint64(s.dur) 28 | cur := s.success / uint64(s.dur) 29 | if cur < uint64(qps) { 30 | panic(fmt.Errorf("qps expect >%d but is %d ", qps, cur)) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/kind/pkg/helper/qps/curl.go: -------------------------------------------------------------------------------- 1 | package qps 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | ) 7 | 8 | func Curl(url string) (string, error) { 9 | c := http.Client{} 10 | req, err := http.NewRequest("GET", url, nil) 11 | if err != nil { 12 | return "", err 13 | } 14 | resp, err := c.Do(req) 15 | if err != nil { 16 | return "", err 17 | } 18 | defer resp.Body.Close() 19 | body, err := ioutil.ReadAll(resp.Body) 20 | if err != nil { 21 | return "", err 22 | } 23 | return string(body), nil 24 | } 25 | -------------------------------------------------------------------------------- /test/kind/pkg/helper/qps/keep-curl_test.go: -------------------------------------------------------------------------------- 1 | package qps 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | "testing" 9 | "time" 10 | 11 | . "alauda.io/alb2/utils/log" 12 | . "alauda.io/alb2/utils/test_utils" 13 | ) 14 | 15 | func TestQps(t *testing.T) { 16 | l := L() 17 | l.Info("ok") 18 | ctx, cancel := CtxWithSignalAndTimeout(5 * 60) 19 | go func() { 20 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 21 | io.WriteString(w, "hello world") 22 | }) 23 | http.ListenAndServe(":8090", nil) 24 | }() 25 | defer cancel() 26 | tctx, xcancel := context.WithTimeout(ctx, time.Second*30) 27 | defer xcancel() 28 | r := NewReqProvider("http://localhost:8090", l, tctx) 29 | r.WithSampleInterval(3) 30 | r.Start() 31 | fmt.Printf("test ok") 32 | s := NewSummaryAssert(r.Summary()) 33 | s.NoError() 34 | s.QpsAbove(300) 35 | } 36 | -------------------------------------------------------------------------------- /timestamp.txt: -------------------------------------------------------------------------------- 1 | Fri, 16 Jun 2023 19:52:57 +0800 2 | -------------------------------------------------------------------------------- /utils/address.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net/url" 5 | "strings" 6 | ) 7 | 8 | func ParseAddressStr(address string) (ip []string, host []string) { 9 | return ParseAddressList(SplitAndRemoveEmpty(address, ",")) 10 | } 11 | 12 | func ParseAddressList(addrs []string) (ip []string, host []string) { 13 | ip = []string{} 14 | host = []string{} 15 | for _, addr := range addrs { 16 | addr = strings.TrimSpace(addr) 17 | if addr == "" { 18 | continue 19 | } 20 | v4, v6, hostname, err := addressIs(addr) 21 | if err != nil { 22 | continue 23 | } 24 | if v4 || v6 { 25 | ip = append(ip, addr) 26 | } 27 | if hostname { 28 | host = append(host, addr) 29 | } 30 | } 31 | return ip, host 32 | } 33 | 34 | func addressIs(address string) (ipv4 bool, ipv6 bool, domain bool, err error) { 35 | if IsValidIPv4(address) { 36 | return true, false, false, nil 37 | } 38 | if IsValidIPv6(address) { 39 | return false, true, false, nil 40 | } 41 | _, err = url.Parse(address) 42 | if err != nil { 43 | return false, false, false, err 44 | } 45 | return false, false, true, nil 46 | } 47 | -------------------------------------------------------------------------------- /utils/consts.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | const ( 4 | OP_AND = "AND" 5 | OP_EXIST = "EXIST" 6 | OP_EQ = "EQ" 7 | OP_IN = "IN" 8 | OP_OR = "OR" 9 | OP_RANGE = "RANGE" 10 | OP_REGEX = "REGEX" 11 | OP_STARTS_WITH = "STARTS_WITH" 12 | OP_ENDS_WITH = "ENDS_WITH" 13 | 14 | KEY_HOST = "HOST" 15 | KEY_URL = "URL" 16 | KEY_SRC_IP = "SRC_IP" 17 | KEY_HEADER = "HEADER" 18 | KEY_COOKIE = "COOKIE" 19 | KEY_PARAM = "PARAM" 20 | KEY_METHOD = "METHOD" 21 | ) 22 | -------------------------------------------------------------------------------- /utils/dirhash/hash_test.go: -------------------------------------------------------------------------------- 1 | // Copy from https://github.com/golang/mod/blob/master/sumdb/dirhash/hash.go 2 | package dirhash 3 | 4 | import ( 5 | "crypto/sha256" 6 | "encoding/base32" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestLabelSafeHash(t *testing.T) { 14 | origin := "a" + strings.Repeat("b", 1000) 15 | h := sha256.New() 16 | h.Write([]byte(origin)) 17 | sha256Result := h.Sum(nil) 18 | str := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(sha256Result) 19 | t.Logf("str %s %v", str, len(str)) 20 | assert.Equal(t, true, len(str) == 52) 21 | } 22 | -------------------------------------------------------------------------------- /utils/log/log_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestLog(_ *testing.T) { 8 | l := L() 9 | l.V(-100).Info("test v-100") 10 | l.V(-3).Info("test v-3") 11 | l.V(-2).Info("test v-2") 12 | l.V(-1).Info("test v-1") 13 | l.V(0).Info("test v0") 14 | l.V(1).Info("test v1") 15 | l.V(2).Info("test v2") 16 | l.V(3).Info("test v3") 17 | l.V(4).Info("test v4") 18 | l.V(5).Info("test v5") 19 | 20 | l.Info("test tagged", "a", "b") 21 | l.WithName("name1").Info("test with name", "a", "b") 22 | l.WithName("name1").WithName("name2").Info("test with name", "a", "b") 23 | 24 | { 25 | l := InitKlogV2(LogCfg{ToFile: "./test.log"}) 26 | l.Info("test other log") 27 | Flush() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /utils/net_utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | ) 7 | 8 | func IsIPv4(address string) bool { 9 | return strings.Count(address, ":") < 2 10 | } 11 | 12 | func IsValidIPv4(address string) bool { 13 | if !IsIPv4(address) { 14 | return false 15 | } 16 | return net.ParseIP(address) != nil 17 | } 18 | 19 | func IsIPv6(address string) bool { 20 | return strings.Count(address, ":") >= 2 21 | } 22 | 23 | func IsValidIPv6(address string) bool { 24 | if !IsIPv6(address) { 25 | return false 26 | } 27 | return net.ParseIP(address) != nil 28 | } 29 | 30 | func IsIPv6Link(address string) bool { 31 | return strings.Count(address, ":") >= 2 && strings.HasPrefix(address, "fe80") 32 | } 33 | -------------------------------------------------------------------------------- /utils/string_ext.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/samber/lo" 7 | ) 8 | 9 | func StrIsNillOrEq(left *string, right string) bool { 10 | return left == nil || (left != nil && *left == right) 11 | } 12 | 13 | func StrListRemoveDuplicates(list []string) []string { 14 | m := make(map[string]string) 15 | for _, x := range list { 16 | m[x] = x 17 | } 18 | var ClearedArr []string 19 | for x := range m { 20 | ClearedArr = append(ClearedArr, x) 21 | } 22 | return ClearedArr 23 | } 24 | 25 | func SplitAndRemoveEmpty(s string, sep string) []string { 26 | items := strings.Split(s, sep) 27 | return lo.Filter(items, func(s string, _ int) bool { return strings.TrimSpace(s) != "" }) 28 | } 29 | -------------------------------------------------------------------------------- /utils/string_ext_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStringSplit(t *testing.T) { 11 | assert.Equal(t, strings.Split("", ","), []string{""}) 12 | assert.Equal(t, SplitAndRemoveEmpty("", ","), []string{}) 13 | } 14 | -------------------------------------------------------------------------------- /utils/test_utils/assert/alb.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "context" 5 | 6 | a2t "alauda.io/alb2/pkg/apis/alauda/v2beta1" 7 | "github.com/go-logr/logr" 8 | "k8s.io/apimachinery/pkg/api/errors" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | 11 | . "alauda.io/alb2/utils/test_utils" 12 | ) 13 | 14 | func WaitAlbReady(cli *K8sClient, log logr.Logger, ctx context.Context, ns string, name string) *a2t.ALB2 { 15 | return WaitAlbState(cli, log, ctx, ns, name, func(alb *a2t.ALB2) (bool, error) { 16 | return alb.Status.State == a2t.ALB2StateRunning, nil 17 | }) 18 | } 19 | 20 | func WaitAlbState(cli *K8sClient, log logr.Logger, ctx context.Context, ns string, name string, check func(alb *a2t.ALB2) (bool, error)) *a2t.ALB2 { 21 | var globalAlb *a2t.ALB2 22 | Wait(func() (bool, error) { 23 | alb, err := cli.GetAlbClient().CrdV2beta1().ALB2s(ns).Get(context.Background(), name, metav1.GetOptions{}) 24 | log.Info("try get alb ", "ns", ns, "name", name) 25 | if errors.IsNotFound(err) { 26 | return false, nil 27 | } 28 | if err != nil { 29 | return false, err 30 | } 31 | ok, err := check(alb) 32 | if err == nil { 33 | globalAlb = alb 34 | return ok, nil 35 | } 36 | return ok, err 37 | }) 38 | return globalAlb 39 | } 40 | -------------------------------------------------------------------------------- /utils/test_utils/assert/deployment.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | . "alauda.io/alb2/utils/test_utils" 8 | "github.com/go-logr/logr" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | ) 11 | 12 | type DeploymentAssert struct { 13 | kc *K8sClient 14 | log logr.Logger 15 | } 16 | 17 | func NewDeploymentAssert(kc *K8sClient, log logr.Logger) *DeploymentAssert { 18 | return &DeploymentAssert{ 19 | kc: kc, 20 | log: log, 21 | } 22 | } 23 | 24 | func (d *DeploymentAssert) WaitReady(ctx context.Context, name string, ns string) { 25 | cli := d.kc.GetK8sClient().AppsV1().Deployments(ns) 26 | for { 27 | time.Sleep(time.Second * 1) 28 | depl, err := cli.Get(ctx, name, metav1.GetOptions{}) 29 | if err != nil { 30 | d.log.Error(err, "get deployment", "name", name, "ns", ns) 31 | continue 32 | } 33 | 34 | if depl.Status.AvailableReplicas != *depl.Spec.Replicas { 35 | d.log.Info("deployment not ready", "depl", PrettyCr(depl)) 36 | continue 37 | } 38 | return 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /utils/test_utils/assert/ingress.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | mapset "github.com/deckarep/golang-set/v2" 5 | "github.com/samber/lo" 6 | n1 "k8s.io/api/networking/v1" 7 | ) 8 | 9 | type IngressAssert struct { 10 | ing *n1.Ingress 11 | } 12 | 13 | func NewIngressAssert(ing *n1.Ingress) *IngressAssert { 14 | return &IngressAssert{ 15 | ing: ing, 16 | } 17 | } 18 | 19 | func (i *IngressAssert) HasLoadBalancerIP(ip string) bool { 20 | for _, lb := range i.ing.Status.LoadBalancer.Ingress { 21 | if lb.IP == ip { 22 | return true 23 | } 24 | } 25 | return false 26 | } 27 | 28 | func (i *IngressAssert) HasLoadBalancerHost(host string) bool { 29 | for _, lb := range i.ing.Status.LoadBalancer.Ingress { 30 | if lb.Hostname == host { 31 | return true 32 | } 33 | } 34 | return false 35 | } 36 | 37 | func (i *IngressAssert) HasLoadBalancerHostAndPort(host string, port []int32) bool { 38 | pmap := mapset.NewSet(port...) 39 | for _, lb := range i.ing.Status.LoadBalancer.Ingress { 40 | if lb.Hostname != host { 41 | continue 42 | } 43 | ports := mapset.NewSet(lo.Map(lb.Ports, func(p n1.IngressPortStatus, _ int) int32 { 44 | return p.Port 45 | })...) 46 | if ports.IsSuperset(pmap) { 47 | return true 48 | } 49 | } 50 | return false 51 | } 52 | -------------------------------------------------------------------------------- /utils/test_utils/console_logger.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-logr/logr" 7 | ) 8 | 9 | type ConsoleLogSink struct { 10 | prefix string 11 | } 12 | 13 | func ConsoleLog() logr.Logger { 14 | return logr.New(ConsoleLogSink{}) 15 | } 16 | 17 | func (l ConsoleLogSink) Init(logr.RuntimeInfo) { 18 | } 19 | 20 | func (l ConsoleLogSink) Enabled(int) bool { 21 | return true 22 | } 23 | 24 | func (l ConsoleLogSink) log(msg string) { 25 | fmt.Println(msg) 26 | } 27 | 28 | func (l ConsoleLogSink) Info(level int, msg string, kv ...interface{}) { 29 | l.log(fmt.Sprintf("%s level %d %s %s %v ", nowStamp(), level, l.prefix, msg, kv)) 30 | } 31 | 32 | func (l ConsoleLogSink) Error(err error, msg string, kv ...interface{}) { 33 | l.log(fmt.Sprintf("%s err %v %s %s %v ", nowStamp(), err, l.prefix, msg, kv)) 34 | } 35 | 36 | func (l ConsoleLogSink) WithValues(kv ...interface{}) logr.LogSink { 37 | return ConsoleLogSink{prefix: fmt.Sprintf("%s %v", l.prefix, kv)} 38 | } 39 | 40 | func (l ConsoleLogSink) WithName(msg string) logr.LogSink { 41 | return ConsoleLogSink{prefix: fmt.Sprintf("%s %v", l.prefix, msg)} 42 | } 43 | -------------------------------------------------------------------------------- /utils/test_utils/docker-ext_test.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestDockerHasImage(t *testing.T) { 8 | d := NewDockerExt(ConsoleLog()) 9 | has, err := d.HasImage("registry.alauda.cn:60080/acp/alb2:local") 10 | t.Logf("%v %v", has, err) 11 | } 12 | -------------------------------------------------------------------------------- /utils/test_utils/eq.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | ) 7 | 8 | func StringsEq(left, right []string) bool { 9 | if len(left) != len(right) { 10 | return false 11 | } 12 | sort.Strings(left) 13 | sort.Strings(right) 14 | return reflect.DeepEqual(left, right) 15 | } 16 | -------------------------------------------------------------------------------- /utils/test_utils/ginkgo_ext.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/go-logr/logr" 7 | "github.com/onsi/gomega" 8 | ) 9 | 10 | func nowStamp() string { 11 | return time.Now().Format(time.StampMilli) 12 | } 13 | 14 | func EventuallySuccess(f func(g gomega.Gomega), log logr.Logger) { 15 | gomega.Eventually(func(g gomega.Gomega) { 16 | log.Info("check") 17 | f(g) 18 | }, "10m", "2s").Should(gomega.Succeed(), func(message string, callerSkip ...int) { 19 | }) 20 | } 21 | 22 | func GNoErr(g gomega.Gomega, err error) { 23 | g.Expect(err).ShouldNot(gomega.HaveOccurred()) 24 | } 25 | 26 | func GEqual(g gomega.Gomega, left interface{}, right interface{}) { 27 | g.Expect(left).Should(gomega.Equal(right)) 28 | } 29 | -------------------------------------------------------------------------------- /utils/test_utils/ginkgo_logger.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-logr/logr" 7 | "github.com/onsi/ginkgo/v2" 8 | ) 9 | 10 | type GinkgoLogSink struct { 11 | prefix string 12 | } 13 | 14 | // Deprecated 15 | // 字符串中含有%时, %v的处理是错的.. 16 | func GinkgoLog() logr.Logger { 17 | return logr.New(GinkgoLogSink{}) 18 | } 19 | 20 | func (l GinkgoLogSink) Init(logr.RuntimeInfo) { 21 | } 22 | 23 | func (l GinkgoLogSink) Enabled(int) bool { 24 | return true 25 | } 26 | 27 | func (l GinkgoLogSink) log(msg string) { 28 | fmt.Fprintf(ginkgo.GinkgoWriter, msg+"\n") 29 | } 30 | 31 | func (l GinkgoLogSink) Info(level int, msg string, kv ...interface{}) { 32 | l.log(fmt.Sprintf("%s level %d %s %s %v", nowStamp(), level, l.prefix, msg, kv)) 33 | } 34 | 35 | func (l GinkgoLogSink) Error(err error, msg string, kv ...interface{}) { 36 | l.log(fmt.Sprintf("%s err %v %s %s %v ", nowStamp(), err, l.prefix, msg, kv)) 37 | } 38 | 39 | func (l GinkgoLogSink) WithValues(kv ...interface{}) logr.LogSink { 40 | return GinkgoLogSink{prefix: fmt.Sprintf("%s %v", l.prefix, kv)} 41 | } 42 | 43 | func (l GinkgoLogSink) WithName(msg string) logr.LogSink { 44 | return GinkgoLogSink{prefix: fmt.Sprintf("%s %v", l.prefix, msg)} 45 | } 46 | -------------------------------------------------------------------------------- /utils/test_utils/json.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import "github.com/wI2L/jsondiff" 4 | 5 | func JsonBelongsTO(left, right interface{}) (bool, interface{}, error) { 6 | patch, err := jsondiff.Compare(left, right) 7 | if err != nil { 8 | return false, nil, err 9 | } 10 | for _, v := range patch { 11 | if v.Type != "remove" { 12 | return false, patch, nil 13 | } 14 | } 15 | return true, patch, nil 16 | } 17 | -------------------------------------------------------------------------------- /utils/test_utils/kind-ext_test.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "testing" 5 | 6 | "alauda.io/alb2/utils/log" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestGetConfig(t *testing.T) { 11 | t.Skip("dev") 12 | c := KindConfig{ 13 | Name: "alb-dual", 14 | Image: "kindest/node:v1.24.3", 15 | ClusterYaml: ` 16 | kind: Cluster 17 | apiVersion: kind.x-k8s.io/v1alpha4 18 | networking: 19 | ipFamily: dual 20 | apiServerAddress: "127.0.0.1" 21 | nodes: 22 | - role: control-plane 23 | - role: worker 24 | - role: worker 25 | `, 26 | } 27 | l := log.L() 28 | 29 | base := InitBase() 30 | kd, err := DeployOrAdopt(c, base, "alb-dual", l) 31 | assert.NoError(t, err) 32 | cfg, err := kd.GetConfig() 33 | assert.NoError(t, err) 34 | k := NewKubectl(base, cfg, l) 35 | out, err := k.Kubectl("get", "nodes") 36 | t.Log(out) 37 | assert.NoError(t, err) 38 | } 39 | -------------------------------------------------------------------------------- /utils/test_utils/util_test.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestGenCert(t *testing.T) { 10 | key, cert, err := GenCert("a.b.c") 11 | assert.NoError(t, err) 12 | t.Logf("key %s", key) 13 | t.Logf("cert %s ", cert) 14 | } 15 | 16 | func TestTemplate(t *testing.T) { 17 | ts := ` 18 | a: {{.Values.x}} 19 | {{- if eq .Values.b "true" }} 20 | b: 1 21 | {{- end}} 22 | {{- if .Values.c }} 23 | c: 1 24 | {{- end}} 25 | ` 26 | out := Template(ts, map[string]interface{}{ 27 | "Values": map[string]interface{}{ 28 | "x": "1", 29 | "b": "false", 30 | "c": true, 31 | }, 32 | }) 33 | assert.Equal(t, out, ` 34 | a: 1 35 | c: 1 36 | `) 37 | t.Log(out) 38 | } 39 | -------------------------------------------------------------------------------- /utils/test_utils/yq.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | ) 9 | 10 | type Yq struct { 11 | Base string 12 | } 13 | 14 | func YqDo(raw string, cmd string) (string, error) { 15 | // only use for test 16 | raw = strings.TrimSpace(raw) 17 | base, err := os.MkdirTemp("", "yq") 18 | if err != nil { 19 | return "", err 20 | } 21 | p := base + "/" + "x.yaml" 22 | err = os.WriteFile(p, []byte(raw), 0o666) 23 | if err != nil { 24 | return "", err 25 | } 26 | sh := fmt.Sprintf(`#!/bin/bash 27 | cat %s | %s 28 | `, p, cmd) 29 | os.WriteFile(base+"/x.sh", []byte(sh), 0o666) 30 | sh_p := base + "/x.sh" 31 | out, err := exec.Command("bash", sh_p).CombinedOutput() 32 | if err != nil { 33 | return "", fmt.Errorf("eval %s fail %v", sh_p, err) 34 | } 35 | return strings.TrimSpace(string(out)), nil 36 | } 37 | -------------------------------------------------------------------------------- /utils/test_utils/yq_test.go: -------------------------------------------------------------------------------- 1 | package test_utils 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestYq(t *testing.T) { 11 | raw := ` 12 | apiVersion: networking.k8s.io/v1 13 | kind: Ingress 14 | metadata: 15 | name: auth-check-cookies 16 | namespace: default 17 | spec: 18 | rules: 19 | - host: "auth-check-cookies" 20 | http: 21 | paths: 22 | - backend: 23 | service: 24 | name: auth-server 25 | port: 26 | number: 80 27 | path: / 28 | pathType: Prefix` 29 | expect := strings.TrimSpace(` 30 | apiVersion: networking.k8s.io/v1 31 | kind: Ingress 32 | metadata: 33 | name: auth-check-cookies 34 | namespace: default 35 | spec: 36 | rules: 37 | - host: "auth-check-cookies" 38 | http: 39 | paths: 40 | - backend: 41 | service: 42 | name: auth-server 43 | port: 44 | number: 80 45 | path: / 46 | pathType: Prefix 47 | ingressClassName: nginx`) 48 | out, err := YqDo(raw, `yq ".spec.ingressClassName=\"nginx\""`) 49 | t.Logf("%v | %v", out, err) 50 | assert.NoError(t, err) 51 | _ = expect 52 | _ = out 53 | assert.Equal(t, expect, out) 54 | } 55 | -------------------------------------------------------------------------------- /utils/types.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func SliceToPointerSlice[T any](slice []T) []*T { 4 | pointerSlice := make([]*T, len(slice)) 5 | for i, v := range slice { 6 | x := v 7 | pointerSlice[i] = &x 8 | } 9 | return pointerSlice 10 | } 11 | -------------------------------------------------------------------------------- /utils/wait_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestUtilWithContextAndTimeout(t *testing.T) { 12 | t.Skip("unstable... skip") 13 | // it should run f each period 14 | { 15 | msgChan := make(chan string, 100) 16 | ctx, cancel := context.WithCancel(context.Background()) 17 | go func() { 18 | time.Sleep(120 * time.Millisecond) 19 | cancel() 20 | t.Logf("ctx is done") 21 | }() 22 | isTimeout := UtilWithContextAndTimeout(ctx, func() { 23 | msgChan <- "msg" 24 | }, 10*time.Millisecond, 20*time.Millisecond) 25 | close(msgChan) 26 | count := 0 27 | for msg := range msgChan { 28 | _ = msg 29 | count++ 30 | } 31 | t.Logf("count is %v\n", count) 32 | assert.Equal(t, isTimeout, false) 33 | } 34 | // it should return with true , if f reach timeout 35 | { 36 | msgChan := make(chan string) 37 | isTimeout := UtilWithContextAndTimeout(context.Background(), func() { 38 | time.Sleep(100 * time.Second) 39 | msgChan <- "should never send" 40 | }, 10*time.Millisecond, 20*time.Millisecond) 41 | assert.Equal(t, isTimeout, true) 42 | select { 43 | case <-msgChan: 44 | assert.Fail(t, "should never receive msg") 45 | default: 46 | assert.True(t, true, "no msg from chan") 47 | } 48 | } 49 | } 50 | --------------------------------------------------------------------------------