|
|
@@ -7,6 +7,9 @@ import (
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
+ "github.com/porter-dev/porter/internal/telemetry"
|
|
|
+
|
|
|
+ "github.com/aws/aws-sdk-go/aws/arn"
|
|
|
"github.com/aws/aws-sdk-go/service/ecr"
|
|
|
"github.com/bufbuild/connect-go"
|
|
|
porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
|
|
|
@@ -18,9 +21,6 @@ import (
|
|
|
"github.com/porter-dev/porter/internal/models"
|
|
|
"github.com/porter-dev/porter/internal/oauth"
|
|
|
"github.com/porter-dev/porter/internal/registry"
|
|
|
- "github.com/porter-dev/porter/internal/telemetry"
|
|
|
-
|
|
|
- "github.com/aws/aws-sdk-go/aws/arn"
|
|
|
)
|
|
|
|
|
|
type RegistryGetECRTokenHandler struct {
|
|
|
@@ -402,33 +402,110 @@ func NewRegistryGetACRTokenHandler(
|
|
|
}
|
|
|
|
|
|
func (c *RegistryGetACRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
- proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
|
|
|
+ ctx, span := telemetry.NewSpan(r.Context(), "serve-acr-token")
|
|
|
+ defer span.End()
|
|
|
+
|
|
|
+ proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
|
|
|
+
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "project-id", Value: proj.ID})
|
|
|
+
|
|
|
+ request := &types.GetRegistryACRTokenRequest{}
|
|
|
+
|
|
|
+ if ok := c.DecodeAndValidate(w, r, request); !ok {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "error decoding request")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if request.ServerURL == "" {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "missing server url")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ serverUrl := strings.TrimSuffix(request.ServerURL, "/")
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "server-url", Value: serverUrl})
|
|
|
|
|
|
// list registries and find one that matches the region
|
|
|
regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
|
|
|
if err != nil {
|
|
|
- c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
|
|
|
+ err = telemetry.Error(ctx, span, err, "error getting registries by project id")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var token string
|
|
|
var expiresAt *time.Time
|
|
|
|
|
|
+ var matchingReg *models.Registry
|
|
|
for _, reg := range regs {
|
|
|
- if reg.AzureIntegrationID != 0 && strings.Contains(reg.URL, "azurecr.io") {
|
|
|
- _reg := registry.Registry(*reg)
|
|
|
- username, pw, err := _reg.GetACRCredentials(c.Repo())
|
|
|
- if err != nil {
|
|
|
- c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
|
|
|
- continue
|
|
|
- }
|
|
|
+ if strings.Contains(reg.URL, serverUrl) {
|
|
|
+ matchingReg = reg
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- token = base64.StdEncoding.EncodeToString([]byte(string(username) + ":" + string(pw)))
|
|
|
+ if matchingReg == nil {
|
|
|
+ err := telemetry.Error(ctx, span, err, "no matching registry")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- // we'll just set an arbitrary 30-day expiry time (this is not enforced)
|
|
|
- timeExpires := time.Now().Add(30 * 24 * 3600 * time.Second)
|
|
|
- expiresAt = &timeExpires
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "registry-name", Value: matchingReg.Name})
|
|
|
+
|
|
|
+ if proj.CapiProvisionerEnabled {
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "capi-provisioned", Value: true})
|
|
|
+
|
|
|
+ if c.Config().ClusterControlPlaneClient == nil {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "cluster control plane client cannot be nil")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ tokenReq := connect.NewRequest(&porterv1.TokenForRegistryRequest{
|
|
|
+ ProjectId: int64(proj.ID),
|
|
|
+ RegistryUri: matchingReg.URL,
|
|
|
+ })
|
|
|
+ tokenResp, err := c.Config().ClusterControlPlaneClient.TokenForRegistry(ctx, tokenReq)
|
|
|
+ if err != nil {
|
|
|
+ err = telemetry.Error(ctx, span, err, "error getting token response from ccp")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if tokenResp.Msg == nil || tokenResp.Msg.Token == "" {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "no token found in response")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ token = tokenResp.Msg.Token
|
|
|
+
|
|
|
+ // we'll just set an arbitrary 30-day expiry time (this is not enforced)
|
|
|
+ timeExpires := time.Now().UTC().Add(30 * 24 * time.Hour)
|
|
|
+ expiresAt = &timeExpires
|
|
|
+ }
|
|
|
+
|
|
|
+ if matchingReg.AzureIntegrationID != 0 {
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "capi-provisioned", Value: false})
|
|
|
+
|
|
|
+ _reg := registry.Registry(*matchingReg)
|
|
|
+ username, pw, err := _reg.GetACRCredentials(c.Repo())
|
|
|
+ if err != nil {
|
|
|
+ err = telemetry.Error(ctx, span, err, "error getting token response from ccp")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
}
|
|
|
+
|
|
|
+ token = base64.StdEncoding.EncodeToString([]byte(string(username) + ":" + string(pw)))
|
|
|
+ // we'll just set an arbitrary 30-day expiry time (this is not enforced)
|
|
|
+ timeExpires := time.Now().UTC().Add(30 * 24 * time.Hour)
|
|
|
+ expiresAt = &timeExpires
|
|
|
+ }
|
|
|
+
|
|
|
+ if token == "" {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "missing token")
|
|
|
+ c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
resp := &types.GetRegistryTokenResponse{
|