-
Notifications
You must be signed in to change notification settings - Fork 192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CFE-1134: Watch infrastructure and update AWS tags #1148
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -12,7 +12,6 @@ import ( | |||||||||||||
"encoding/json" | ||||||||||||||
"errors" | ||||||||||||||
"fmt" | ||||||||||||||
"github.com/aws/aws-sdk-go/service/ec2" | ||||||||||||||
"io" | ||||||||||||||
"io/ioutil" | ||||||||||||||
"net" | ||||||||||||||
|
@@ -32,13 +31,15 @@ import ( | |||||||||||||
iov1 "github.com/openshift/api/operatoringress/v1" | ||||||||||||||
routev1 "github.com/openshift/api/route/v1" | ||||||||||||||
|
||||||||||||||
configclientset "github.com/openshift/client-go/config/clientset/versioned" | ||||||||||||||
"github.com/openshift/cluster-ingress-operator/pkg/manifests" | ||||||||||||||
chiragkyal marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
operatorclient "github.com/openshift/cluster-ingress-operator/pkg/operator/client" | ||||||||||||||
"github.com/openshift/cluster-ingress-operator/pkg/operator/controller" | ||||||||||||||
operatorcontroller "github.com/openshift/cluster-ingress-operator/pkg/operator/controller" | ||||||||||||||
ingresscontroller "github.com/openshift/cluster-ingress-operator/pkg/operator/controller/ingress" | ||||||||||||||
|
||||||||||||||
"github.com/aws/aws-sdk-go/aws/endpoints" | ||||||||||||||
"github.com/aws/aws-sdk-go/service/ec2" | ||||||||||||||
|
||||||||||||||
"github.com/go-logr/logr" | ||||||||||||||
"github.com/stretchr/testify/assert" | ||||||||||||||
|
@@ -116,6 +117,7 @@ var ( | |||||||||||||
|
||||||||||||||
var ( | ||||||||||||||
kclient client.Client | ||||||||||||||
configClient *configclientset.Clientset | ||||||||||||||
dnsConfig configv1.DNS | ||||||||||||||
infraConfig configv1.Infrastructure | ||||||||||||||
operatorNamespace = operatorcontroller.DefaultOperatorNamespace | ||||||||||||||
|
@@ -153,6 +155,12 @@ func TestMain(m *testing.M) { | |||||||||||||
} | ||||||||||||||
kclient = kubeClient | ||||||||||||||
|
||||||||||||||
configClient, err = configclientset.NewForConfig(kubeConfig) | ||||||||||||||
if err != nil { | ||||||||||||||
fmt.Printf("failed to create config client: %s\n", err) | ||||||||||||||
os.Exit(1) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
if err := kclient.Get(context.TODO(), types.NamespacedName{Name: "cluster"}, &dnsConfig); err != nil { | ||||||||||||||
fmt.Printf("failed to get DNS config: %v\n", err) | ||||||||||||||
os.Exit(1) | ||||||||||||||
|
@@ -1291,6 +1299,83 @@ func TestInternalLoadBalancerGlobalAccessGCP(t *testing.T) { | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// TestAWSResourceTagsChanged tests the functionality of updating AWS resource tags | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of the acceptance criteria is: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The test already covers adding a user-defined tag. However, updating the infra status again to remove certain tag is possible, which will update the annotation as well, but the tag won't be removed from the AWS resource itself, and this is an expected behaviour for cloud-provider-aws. See #1148 (comment) for more details. I've extended the test to cover this scenario of tag removal and annotation update in the latest changes. Hope it covers the acceptance criteria. |
||||||||||||||
// in the infrastructure configuration and validates that the expected | ||||||||||||||
// awsLBAdditionalResourceTags is set correctly on the | ||||||||||||||
// loadBalancer service associated with the default Ingress Controller. | ||||||||||||||
// | ||||||||||||||
// This test is a serial test because it modifies the cluster infrastructure config and | ||||||||||||||
// therefore should not run in parallel with other tests. | ||||||||||||||
func TestAWSResourceTagsChanged(t *testing.T) { | ||||||||||||||
if infraConfig.Status.Platform != "AWS" { | ||||||||||||||
t.Skipf("test skipped on platform %q", infraConfig.Status.Platform) | ||||||||||||||
} | ||||||||||||||
if err := waitForIngressControllerCondition(t, kclient, 10*time.Second, defaultName, defaultAvailableConditions...); err != nil { | ||||||||||||||
t.Errorf("did not get expected conditions: %v", err) | ||||||||||||||
} | ||||||||||||||
defaultIC := &operatorv1.IngressController{ | ||||||||||||||
ObjectMeta: metav1.ObjectMeta{ | ||||||||||||||
Namespace: defaultName.Namespace, | ||||||||||||||
Name: defaultName.Name, | ||||||||||||||
}, | ||||||||||||||
} | ||||||||||||||
awsLBAdditionalResourceTags := "service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags" | ||||||||||||||
|
||||||||||||||
// Save a copy of the original infraConfig, to revert changes before exiting. | ||||||||||||||
originalInfra := infraConfig.DeepCopy() | ||||||||||||||
t.Cleanup(func() { | ||||||||||||||
err := updateInfrastructureConfigStatusWithRetryOnConflict(t, 5*time.Minute, configClient, func(infra *configv1.Infrastructure) *configv1.Infrastructure { | ||||||||||||||
infra.Status = originalInfra.Status | ||||||||||||||
return infra | ||||||||||||||
}) | ||||||||||||||
if err != nil { | ||||||||||||||
t.Logf("Unable to remove changes from the infraConfig, possible corruption of test environment: %v", err) | ||||||||||||||
} | ||||||||||||||
}) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like this:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, updated. |
||||||||||||||
|
||||||||||||||
initialTags := []configv1.AWSResourceTag{ | ||||||||||||||
{Key: "Key1", Value: "Value1"}, | ||||||||||||||
{Key: "Key2", Value: "Value2"}, | ||||||||||||||
} | ||||||||||||||
t.Logf("Updating AWS ResourceTags in the cluster infrastructure config: %v", initialTags) | ||||||||||||||
err := updateInfrastructureConfigStatusWithRetryOnConflict(t, 5*time.Minute, configClient, func(infra *configv1.Infrastructure) *configv1.Infrastructure { | ||||||||||||||
if infra.Status.PlatformStatus == nil { | ||||||||||||||
infra.Status.PlatformStatus = &configv1.PlatformStatus{} | ||||||||||||||
} | ||||||||||||||
if infra.Status.PlatformStatus.AWS == nil { | ||||||||||||||
infra.Status.PlatformStatus.AWS = &configv1.AWSPlatformStatus{} | ||||||||||||||
} | ||||||||||||||
infra.Status.PlatformStatus.AWS.ResourceTags = initialTags | ||||||||||||||
return infra | ||||||||||||||
}) | ||||||||||||||
if err != nil { | ||||||||||||||
t.Errorf("failed to update infrastructure status: %v", err) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
chiragkyal marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
// Check awsLBAdditionalResourceTags annotation with initial tags. | ||||||||||||||
expectedTags := "Key1=Value1,Key2=Value2" | ||||||||||||||
t.Logf("Validating the %s annotation for the load balancer service of the default ingresscontroller", awsLBAdditionalResourceTags) | ||||||||||||||
assertLoadBalancerServiceAnnotationWithPollImmediate(t, kclient, defaultIC, awsLBAdditionalResourceTags, expectedTags) | ||||||||||||||
|
||||||||||||||
// Update the status again, removing one tag. | ||||||||||||||
updatedTags := []configv1.AWSResourceTag{ | ||||||||||||||
{Key: "Key1", Value: "Value1"}, | ||||||||||||||
} | ||||||||||||||
t.Logf("Updating AWS ResourceTags in the cluster infrastructure config: %v", updatedTags) | ||||||||||||||
err = updateInfrastructureConfigStatusWithRetryOnConflict(t, 5*time.Minute, configClient, func(infra *configv1.Infrastructure) *configv1.Infrastructure { | ||||||||||||||
infra.Status.PlatformStatus.AWS.ResourceTags = updatedTags | ||||||||||||||
return infra | ||||||||||||||
}) | ||||||||||||||
if err != nil { | ||||||||||||||
t.Errorf("failed to update infrastructure status: %v", err) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Check awsLBAdditionalResourceTags annotation with updated tags. | ||||||||||||||
expectedTags = "Key1=Value1" | ||||||||||||||
t.Logf("Validating the %s annotation for the load balancer service of the default ingresscontroller", awsLBAdditionalResourceTags) | ||||||||||||||
assertLoadBalancerServiceAnnotationWithPollImmediate(t, kclient, defaultIC, awsLBAdditionalResourceTags, expectedTags) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
func TestAWSLBTypeChange(t *testing.T) { | ||||||||||||||
t.Parallel() | ||||||||||||||
|
||||||||||||||
|
@@ -4323,6 +4408,29 @@ func assertServiceAnnotation(t *testing.T, serviceName types.NamespacedName, ann | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// assertLoadBalancerServiceAnnotationWithPollImmediate checks if the specified annotation on the | ||||||||||||||
// LoadBalancer Service of the given IngressController matches the expected value. | ||||||||||||||
func assertLoadBalancerServiceAnnotationWithPollImmediate(t *testing.T, kclient client.Client, ic *operatorv1.IngressController, annotationKey, expectedValue string) { | ||||||||||||||
err := wait.PollUntilContextTimeout(context.Background(), 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { | ||||||||||||||
service := &corev1.Service{} | ||||||||||||||
if err := kclient.Get(ctx, controller.LoadBalancerServiceName(ic), service); err != nil { | ||||||||||||||
t.Logf("failed to get service %s: %v, retrying...", controller.LoadBalancerServiceName(ic), err) | ||||||||||||||
return false, nil | ||||||||||||||
} | ||||||||||||||
if actualValue, ok := service.Annotations[annotationKey]; !ok { | ||||||||||||||
t.Logf("load balancer has no %q annotation yet: %v, retrying...", annotationKey, service.Annotations) | ||||||||||||||
return false, nil | ||||||||||||||
} else if actualValue != expectedValue { | ||||||||||||||
t.Logf("expected %s, found %s", expectedValue, actualValue) | ||||||||||||||
return false, nil | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expect that we don't want to keep trying, after we found an unexpected value. Or would we expect it change after this?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to keep trying here because the annotation value might not get updated immediately after the infra status is updated. |
||||||||||||||
} | ||||||||||||||
return true, nil | ||||||||||||||
}) | ||||||||||||||
if err != nil { | ||||||||||||||
t.Fatalf("timed out waiting for the %s annotation to be updated: %v", annotationKey, err) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// assertServiceNotDeleted asserts that a provide service wasn't deleted. | ||||||||||||||
func assertServiceNotDeleted(t *testing.T, serviceName types.NamespacedName, oldUid types.UID) { | ||||||||||||||
t.Helper() | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other watches technically should have this predicate too, and
ingressConfigToIngressController
should be renamed. However, adding the predicate to the other watches and renaming the map function should be addressed in a follow-up.