Skip to content

Commit

Permalink
OCPBUGS-32233: Not able to enable repositories during entitled build …
Browse files Browse the repository at this point in the history
…in OCP Cluster on IBM-Z (#991)

Co-authored-by: José Luis Segura Lucas <joseluis@redhat.com>
  • Loading branch information
openshift-cherrypick-robot and joselsegura authored Sep 5, 2024
1 parent 8024649 commit fe90706
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 29 deletions.
4 changes: 2 additions & 2 deletions pkg/controller/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,9 @@ func (s *Operator) Run(ctx context.Context, controller *controllercmd.Controller
return fmt.Errorf("unable to set initial cluster status: %v", err)
}

scaController := sca.New(ctx, kubeClient.CoreV1(), configAggregator, insightsClient)
scaController := sca.New(kubeClient.CoreV1(), configAggregator, insightsClient)
statusReporter.AddSources(scaController)
go scaController.Run()
go scaController.Run(ctx)

clusterTransferController := clustertransfer.New(ctx, kubeClient.CoreV1(), configAggregator, insightsClient)
statusReporter.AddSources(clusterTransferController)
Expand Down
2 changes: 1 addition & 1 deletion pkg/insights/insightsclient/insightsclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
const (
responseBodyLogLen = 1024
insightsReqId = "x-rh-insights-request-id"
scaArchPayload = `{"type": "sca","arch": "x86_64"}`
scaArchPayload = `{"type": "sca","arch": "%s"}`
)

type Client struct {
Expand Down
6 changes: 4 additions & 2 deletions pkg/insights/insightsclient/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (c *Client) RecvReport(ctx context.Context, endpoint string) (*http.Respons
return nil, fmt.Errorf("report response status code: %d", resp.StatusCode)
}

func (c *Client) RecvSCACerts(_ context.Context, endpoint string) ([]byte, error) {
func (c *Client) RecvSCACerts(_ context.Context, endpoint string, architecture string) ([]byte, error) {
cv, err := c.GetClusterVersion()
if apierrors.IsNotFound(err) {
return nil, ErrWaitingForVersion
Expand All @@ -192,14 +192,16 @@ func (c *Client) RecvSCACerts(_ context.Context, endpoint string) ([]byte, error
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer([]byte(scaArchPayload)))
payload := fmt.Sprintf(scaArchPayload, architecture)
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer([]byte(payload)))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
c.client.Transport = clientTransport(c.authorizer)
authHeader := fmt.Sprintf("AccessToken %s:%s", cv.Spec.ClusterID, token)
req.Header.Set("Authorization", authHeader)
klog.Infof("Asking for SCA certificate for %s architecture", architecture)

resp, err := c.client.Do(req)
if err != nil {
Expand Down
55 changes: 35 additions & 20 deletions pkg/ocm/sca/sca.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"runtime"
"strings"
"time"

Expand Down Expand Up @@ -34,7 +35,6 @@ const (
type Controller struct {
controllerstatus.StatusController
coreClient corev1client.CoreV1Interface
ctx context.Context
configurator configobserver.Interface
client *insightsclient.Client
}
Expand All @@ -48,33 +48,32 @@ type Response struct {
}

// New creates new instance
func New(ctx context.Context, coreClient corev1client.CoreV1Interface, configurator configobserver.Interface,
func New(coreClient corev1client.CoreV1Interface, configurator configobserver.Interface,
insightsClient *insightsclient.Client) *Controller {
return &Controller{
StatusController: controllerstatus.New(ControllerName),
coreClient: coreClient,
ctx: ctx,
configurator: configurator,
client: insightsClient,
}
}

// Run periodically queries the OCM API and update corresponding secret accordingly
func (c *Controller) Run() {
func (c *Controller) Run(ctx context.Context) {
cfg := c.configurator.Config()
endpoint := cfg.SCA.Endpoint
interval := cfg.SCA.Interval
disabled := cfg.SCA.Disabled
configCh, cancel := c.configurator.ConfigChanged()
defer cancel()
if !disabled {
c.requestDataAndCheckSecret(endpoint)
c.requestDataAndCheckSecret(ctx, endpoint)
}
for {
select {
case <-time.After(interval):
if !disabled {
c.requestDataAndCheckSecret(endpoint)
c.requestDataAndCheckSecret(ctx, endpoint)
} else {
msg := "Pulling of the SCA certs from the OCM API is disabled"
klog.Warning(msg)
Expand All @@ -95,10 +94,11 @@ func (c *Controller) Run() {
}
}

func (c *Controller) requestDataAndCheckSecret(endpoint string) {
func (c *Controller) requestDataAndCheckSecret(ctx context.Context, endpoint string) {
klog.Infof("Pulling SCA certificates from %s. Next check is in %s", c.configurator.Config().SCA.Endpoint,
c.configurator.Config().SCA.Interval)
data, err := c.requestSCAWithExpBackoff(endpoint)

data, err := c.requestSCAWithExpBackoff(ctx, endpoint)
if err != nil {
httpErr, ok := err.(insightsclient.HttpError)
errMsg := fmt.Sprintf("Failed to pull SCA certs from %s: %v", endpoint, err)
Expand Down Expand Up @@ -131,13 +131,13 @@ func (c *Controller) requestDataAndCheckSecret(endpoint string) {
klog.Errorf("Unable to decode response: %v", err)
return
}

// check & update the secret here
err = c.checkSecret(&ocmRes)
err = c.checkSecret(ctx, &ocmRes)
if err != nil {
klog.Errorf("Error when checking the %s secret: %v", secretName, err)
return
}

klog.Infof("%s secret successfully updated", secretName)
c.StatusController.UpdateStatus(controllerstatus.Summary{
Operation: controllerstatus.PullingSCACerts,
Expand All @@ -151,12 +151,12 @@ func (c *Controller) requestDataAndCheckSecret(endpoint string) {
// checkSecret checks "etc-pki-entitlement" secret in the "openshift-config-managed" namespace.
// If the secret doesn't exist then it will create a new one.
// If the secret already exist then it will update the data.
func (c *Controller) checkSecret(ocmData *Response) error {
scaSec, err := c.coreClient.Secrets(targetNamespaceName).Get(c.ctx, secretName, metav1.GetOptions{})
func (c *Controller) checkSecret(ctx context.Context, ocmData *Response) error {
scaSec, err := c.coreClient.Secrets(targetNamespaceName).Get(ctx, secretName, metav1.GetOptions{})

// if the secret doesn't exist then create one
if errors.IsNotFound(err) {
_, err = c.createSecret(ocmData)
_, err = c.createSecret(ctx, ocmData)
if err != nil {
return err
}
Expand All @@ -166,14 +166,14 @@ func (c *Controller) checkSecret(ocmData *Response) error {
return err
}

_, err = c.updateSecret(scaSec, ocmData)
_, err = c.updateSecret(ctx, scaSec, ocmData)
if err != nil {
return err
}
return nil
}

func (c *Controller) createSecret(ocmData *Response) (*v1.Secret, error) {
func (c *Controller) createSecret(ctx context.Context, ocmData *Response) (*v1.Secret, error) {
newSCA := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Expand All @@ -185,41 +185,56 @@ func (c *Controller) createSecret(ocmData *Response) (*v1.Secret, error) {
},
Type: v1.SecretTypeOpaque,
}
cm, err := c.coreClient.Secrets(targetNamespaceName).Create(c.ctx, newSCA, metav1.CreateOptions{})
cm, err := c.coreClient.Secrets(targetNamespaceName).Create(ctx, newSCA, metav1.CreateOptions{})
if err != nil {
return nil, err
}
return cm, nil
}

// updateSecret updates provided secret with given data
func (c *Controller) updateSecret(s *v1.Secret, ocmData *Response) (*v1.Secret, error) {
func (c *Controller) updateSecret(ctx context.Context, s *v1.Secret, ocmData *Response) (*v1.Secret, error) {
s.Data = map[string][]byte{
entitlementAttrName: []byte(ocmData.Cert),
entitlementKeyAttrName: []byte(ocmData.Key),
}
s, err := c.coreClient.Secrets(s.Namespace).Update(c.ctx, s, metav1.UpdateOptions{})
s, err := c.coreClient.Secrets(s.Namespace).Update(ctx, s, metav1.UpdateOptions{})
if err != nil {
return nil, err
}
return s, nil
}

// getArch check the value of GOARCH and return a valid representation for
// OCM certificates API
func getArch() string {
validArchs := map[string]string{
"amd64": "x86_64",
"i386": "x86",
}

if translation, ok := validArchs[runtime.GOARCH]; ok {
return translation
}
return runtime.GOARCH
}

// requestSCAWithExpBackoff queries OCM API with exponential backoff.
// Returns HttpError (see insightsclient.go) in case of any HTTP error response from OCM API.
// The exponential backoff is applied only for HTTP errors >= 500.
func (c *Controller) requestSCAWithExpBackoff(endpoint string) ([]byte, error) {
func (c *Controller) requestSCAWithExpBackoff(ctx context.Context, endpoint string) ([]byte, error) {
bo := wait.Backoff{
Duration: c.configurator.Config().SCA.Interval / 32, // 15 min by default
Factor: 2,
Jitter: 0,
Steps: ocm.FailureCountThreshold,
Cap: c.configurator.Config().SCA.Interval,
}

var data []byte
err := wait.ExponentialBackoff(bo, func() (bool, error) {
var err error
data, err = c.client.RecvSCACerts(c.ctx, endpoint)
data, err = c.client.RecvSCACerts(ctx, endpoint, getArch())
if err != nil {
// don't try again in case it's not an HTTP error - it could mean we're in disconnected env
if !insightsclient.IsHttpError(err) {
Expand Down
8 changes: 4 additions & 4 deletions pkg/ocm/sca/sca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ var (
func Test_SCAController_SecretIsCreated(t *testing.T) {
kube := kubefake.NewSimpleClientset()
coreClient := kube.CoreV1()
scaController := New(context.TODO(), coreClient, nil, nil)
scaController := New(coreClient, nil, nil)

testRes := &Response{
Key: "secret key",
Cert: "secret cert",
}
err := scaController.checkSecret(testRes)
err := scaController.checkSecret(context.Background(), testRes)
assert.NoError(t, err, "failed to check the secret")

testSecret, err := coreClient.Secrets(targetNamespaceName).Get(context.Background(), secretName, metav1.GetOptions{})
Expand All @@ -52,12 +52,12 @@ func Test_SCAController_SecretIsUpdated(t *testing.T) {
}
_, err := coreClient.Secrets(targetNamespaceName).Create(context.Background(), existingSec, metav1.CreateOptions{})
assert.NoError(t, err)
scaController := New(context.TODO(), coreClient, nil, nil)
scaController := New(coreClient, nil, nil)
testRes := &Response{
Key: "new secret testing key",
Cert: "new secret testing cert",
}
err = scaController.checkSecret(testRes)
err = scaController.checkSecret(context.Background(), testRes)
assert.NoError(t, err, "failed to check the secret")

testSecret, err := coreClient.Secrets(targetNamespaceName).Get(context.Background(), secretName, metav1.GetOptions{})
Expand Down

0 comments on commit fe90706

Please sign in to comment.