Skip to content

Commit

Permalink
add support for multiple httpproxies
Browse files Browse the repository at this point in the history
Signed-off-by: Nico Piderman <[email protected]>
  • Loading branch information
sneako committed Jun 16, 2023
1 parent 988436b commit edef53a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 41 deletions.
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ Contour supports multiple configuration APIs in order to meet the needs of as ma
- **[Gateway API](https://gateway-api.sigs.k8s.io/)** (beta) - A new CRD-based API managed by the [Kubernetes SIG-Network community](https://github.com/kubernetes/community/tree/master/sig-network) that aims to evolve Kubernetes service networking APIs in a vendor-neutral way.

## How to integrate Contour with Argo Rollouts

NOTES:

***1. The file as follows just for illustrative purposes only, please do not use directly!!!***
**_1. The file as follows just for illustrative purposes only, please do not use directly!!!_**

***2. The argo-rollouts >= [v1.5.0-rc1](https://github.com/argoproj/argo-rollouts/releases/tag/v1.5.0-rc1)***
**_2. The argo-rollouts >= [v1.5.0-rc1](https://github.com/argoproj/argo-rollouts/releases/tag/v1.5.0-rc1)_**

Steps:

1. Run the `yaml/rbac.yaml` to add the role for operate on the `HTTPProxy`.
2. Build this plugin.
3. Put the plugin somewhere & mount on to the container for `argo-rollouts`:

```yaml
apiVersion: apps/v1
kind: Deployment
Expand All @@ -40,7 +42,7 @@ template:
volumeMounts:
- name: contour-plugin
mountPath: /CHANGE-ME/rollouts-trafficrouter-contour-plugin

```

4. Create a ConfigMap to let `argo-rollouts` know the plugin's location:
Expand All @@ -53,14 +55,13 @@ name: argo-rollouts-config
namespace: argo-rollouts
data:
trafficRouterPlugins: |-
- name: "argoproj-labs/contour"
location: "file://CHANGE-ME/rollouts-trafficrouter-contour-plugin/contour-plugin"
- name: "argoproj-labs/contour"
location: "file://CHANGE-ME/rollouts-trafficrouter-contour-plugin/contour-plugin"
binaryData: {}

```
5. Create the `CR/Rollout` and put it into the operated services` namespace:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
Expand All @@ -83,16 +84,16 @@ apiVersion: argoproj.io/v1alpha1
trafficRouting:
plugins:
argoproj-labs/contour:
httpProxy: rollouts-demo
httpProxies:
- rollouts-demo
namespace: rollouts-demo
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: canary
```

6. Enjoy It.

6. Enjoy It.

## TODO: Contribution
62 changes: 32 additions & 30 deletions pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ type RpcPlugin struct {
}

type ContourTrafficRouting struct {
// HTTPProxy refers to the name of the HTTPProxy used to route traffic to the
// service
HTTPProxy string `json:"httpProxy" protobuf:"bytes,1,name=httpProxy"`
// HTTPProxies is an array of strings which refer to the names of the HTTPProxies used to route
// traffic to the service
HTTPProxies []string `json:"httpProxies" protobuf:"bytes,1,name=httpProxies"`
}

func (r *RpcPlugin) InitPlugin() (re pluginTypes.RpcError) {
Expand All @@ -57,7 +57,6 @@ func (r *RpcPlugin) SetWeight(
rollout *v1alpha1.Rollout,
desiredWeight int32,
additionalDestinations []v1alpha1.WeightDestination) (re pluginTypes.RpcError) {

defer func() {
if e := recover(); e != nil {
re.ErrorString = e.(error).Error()
Expand All @@ -75,42 +74,45 @@ func (r *RpcPlugin) SetWeight(
ctr := ContourTrafficRouting{}
utils.Must(json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins["argoproj-labs/contour"], &ctr))

var httpProxy contourv1.HTTPProxy
unstr := utils.Must1(r.dynamicClient.Resource(contourv1.HTTPProxyGVR).Namespace(rollout.Namespace).Get(ctx, ctr.HTTPProxy, metav1.GetOptions{}))
utils.Must(runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.UnstructuredContent(), &httpProxy))
for _, proxy := range ctr.HTTPProxies {
slog.Debug("updating proxy", slog.String("proxy", proxy))

canarySvcName := rollout.Spec.Strategy.Canary.CanaryService
stableSvcName := rollout.Spec.Strategy.Canary.StableService
var httpProxy contourv1.HTTPProxy
unstr := utils.Must1(r.dynamicClient.Resource(contourv1.HTTPProxyGVR).Namespace(rollout.Namespace).Get(ctx, proxy, metav1.GetOptions{}))
utils.Must(runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.UnstructuredContent(), &httpProxy))

slog.Debug("the services name", slog.String("stable", stableSvcName), slog.String("canary", canarySvcName))
canarySvcName := rollout.Spec.Strategy.Canary.CanaryService
stableSvcName := rollout.Spec.Strategy.Canary.StableService

// TODO: filter by condition(s)
services := utils.Must1(getServiceList(httpProxy.Spec.Routes))
canarySvc := utils.Must1(getService(canarySvcName, services))
stableSvc := utils.Must1(getService(stableSvcName, services))
slog.Debug("the services name", slog.String("stable", stableSvcName), slog.String("canary", canarySvcName))

slog.Debug("old weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight))
// TODO: filter by condition(s)
services := utils.Must1(getServiceList(httpProxy.Spec.Routes))
canarySvc := utils.Must1(getService(canarySvcName, services))
stableSvc := utils.Must1(getService(stableSvcName, services))

canarySvc.Weight = int64(desiredWeight)
stableSvc.Weight = 100 - canarySvc.Weight
slog.Debug("old weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight))

slog.Debug("new weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight))
canarySvc.Weight = int64(desiredWeight)
stableSvc.Weight = 100 - canarySvc.Weight

m := utils.Must1(runtime.DefaultUnstructuredConverter.ToUnstructured(&httpProxy))
updated, err := r.dynamicClient.Resource(contourv1.HTTPProxyGVR).Namespace(rollout.Namespace).Update(ctx, &unstructured.Unstructured{Object: m}, metav1.UpdateOptions{})
if err != nil {
slog.Error("update the HTTPProxy is failed", slog.String("name", httpProxy.Name), slog.Any("err", err))
utils.Must(err)
}
slog.Debug("new weight", slog.Int64("canary", canarySvc.Weight), slog.Int64("stable", stableSvc.Weight))

if r.IsTest {
m := utils.Must1(runtime.DefaultUnstructuredConverter.ToUnstructured(&httpProxy))
updated, err := r.dynamicClient.Resource(contourv1.HTTPProxyGVR).Namespace(rollout.Namespace).Update(ctx, &unstructured.Unstructured{Object: m}, metav1.UpdateOptions{})
if err != nil {
slog.Error("update the HTTPProxy is failed", slog.String("name", httpProxy.Name), slog.Any("err", err))
utils.Must(err)
}

proxy := contourv1.HTTPProxy{}
utils.Must(runtime.DefaultUnstructuredConverter.FromUnstructured(updated.UnstructuredContent(), &proxy))
r.UpdatedMockHTTPProxy = &proxy
}
if r.IsTest {
proxy := contourv1.HTTPProxy{}
utils.Must(runtime.DefaultUnstructuredConverter.FromUnstructured(updated.UnstructuredContent(), &proxy))
r.UpdatedMockHTTPProxy = &proxy
}

slog.Info("update HTTPProxy is successfully")
slog.Info("successfully updated HTTPProxy", slog.String("httpproxy", proxy))
}
return
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func TestRunSuccessfully(t *testing.T) {

func newRollout(stableSvc, canarySvc, httpProxyName string) *v1alpha1.Rollout {
contourConfig := ContourTrafficRouting{
HTTPProxy: httpProxyName,
HTTPProxies: []string{httpProxyName},
}
encodedContourConfig, err := json.Marshal(contourConfig)
if err != nil {
Expand Down

0 comments on commit edef53a

Please sign in to comment.