Skip to content
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

Add support for -pushimage to azure registries #1092

Closed
wants to merge 18 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 138 additions & 14 deletions pkg/core/util/repository/azrcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package repository

import (
"bytes"
"context"
"crypto/sha256"
"encoding/json"
Expand All @@ -12,6 +13,7 @@ import (
"io"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry"
Expand All @@ -21,19 +23,9 @@ import (

func getImageSHA(driverConfig *eUtils.DriverConfig, svc *azidentity.ClientSecretCredential, pluginToolConfig map[string]interface{}) error {

if pluginToolConfig["acrrepository"] != nil && len(pluginToolConfig["acrrepository"].(string)) == 0 {
driverConfig.CoreConfig.Log.Printf("Acr repository undefined. Refusing to continue.\n")
return errors.New("undefined acr repository")
}

if !strings.HasPrefix(pluginToolConfig["acrrepository"].(string), "https://") {
driverConfig.CoreConfig.Log.Printf("Malformed Acr repository. https:// required. Refusing to continue.\n")
return errors.New("malformed acr repository - https:// required")
}

if pluginToolConfig["trcplugin"] != nil && len(pluginToolConfig["trcplugin"].(string)) == 0 {
driverConfig.CoreConfig.Log.Printf("Trcplugin undefined. Refusing to continue.\n")
return errors.New("undefined trcplugin")
err := ValidateRepository(driverConfig, pluginToolConfig)
if err != nil {
return err
}

client, err := azcontainerregistry.NewClient(
Expand Down Expand Up @@ -180,6 +172,138 @@ func GetImageAndShaFromDownload(driverConfig *eUtils.DriverConfig, pluginToolCon
}

// Pushes image to docker registry from: "rawImageFile", and "pluginname" in the map pluginToolConfig.
// https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry#readme-examples
func PushImage(driverConfig *eUtils.DriverConfig, pluginToolConfig map[string]interface{}) error {
return errors.New("Not defined")
err := ValidateRepository(driverConfig, pluginToolConfig)

if err != nil {
return err
}

svc, err := azidentity.NewClientSecretCredential(
pluginToolConfig["azureTenantId"].(string),
pluginToolConfig["azureClientId"].(string),
pluginToolConfig["azureClientSecret"].(string),
nil)

if err != nil {
return err
}

client, err := azcontainerregistry.NewClient(
pluginToolConfig["acrrepository"].(string),
svc, nil)

if err != nil {
driverConfig.CoreConfig.Log.Printf("failed to create client: %v", err)
return err
}

blobClient, err := azcontainerregistry.NewBlobClient(
pluginToolConfig["acrrepository"].(string),
svc, nil)

if err != nil {
driverConfig.CoreConfig.Log.Printf("failed to create blob client: %v", err)
return err
}

ctx := context.Background()
startRes, err := blobClient.StartUpload(ctx, pluginToolConfig["trcplugin"].(string), nil)

if err != nil {
return errors.New("failed to start upload layer: " + err.Error())
}

layer := pluginToolConfig["rawImageFile"].([]byte)

calculator := azcontainerregistry.NewBlobDigestCalculator()
uploadResp, err := blobClient.UploadChunk(ctx, *startRes.Location, bytes.NewReader(layer), calculator, nil)

if err != nil {
return errors.New("failed to upload layer: " + err.Error())
}

completeResp, err := blobClient.CompleteUpload(ctx, *uploadResp.Location, calculator, nil)
if err != nil {
return errors.New("failed to complete layer upload: " + err.Error())
}

layerDigest := *completeResp.DockerContentDigest
config := []byte(fmt.Sprintf(`{
architecture: "amd64",
os: "windows",
rootfs: {
type: "layers",
diff_ids: [%s],
},
}`, layerDigest))

startRes, err = blobClient.StartUpload(ctx, pluginToolConfig["trcplugin"].(string), nil)

if err != nil {
return errors.New("failed to start upload config: " + err.Error())
}

calculator = azcontainerregistry.NewBlobDigestCalculator()
uploadResp, err = blobClient.UploadChunk(ctx, *startRes.Location, bytes.NewReader(config), calculator, nil)
if err != nil {
return errors.New("failed to upload config: " + err.Error())
}

completeResp, err = blobClient.CompleteUpload(ctx, *uploadResp.Location, calculator, nil)

if err != nil {
return errors.New("failed to complete upload config: " + err.Error())
}

manifest := fmt.Sprintf(`
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "%s",
"size": %d
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar",
"digest": "%s",
"size": %d,
"annotations": {
"title": "artifact.txt"
}
}
]
}`, layerDigest, len(config), *completeResp.DockerContentDigest, len(layer))

uploadManifestRes, err := client.UploadManifest(ctx, pluginToolConfig["trcplugin"].(string), "1.0.0",
azcontainerregistry.ContentTypeApplicationVndDockerDistributionManifestV2JSON, streaming.NopCloser(bytes.NewReader([]byte(manifest))), nil)

if err != nil {
return errors.New("failed to upload manifest: " + err.Error())
}

driverConfig.CoreConfig.Log.Printf("digest of uploaded manifest: %s", *uploadManifestRes.DockerContentDigest)
return nil
}

func ValidateRepository(driverConfig *eUtils.DriverConfig, pluginToolConfig map[string]interface{}) error {
if pluginToolConfig["acrrepository"] != nil && len(pluginToolConfig["acrrepository"].(string)) == 0 {
driverConfig.CoreConfig.Log.Printf("Acr repository undefined. Refusing to continue.\n")
return errors.New("undefined acr repository")
}

if !strings.HasPrefix(pluginToolConfig["acrrepository"].(string), "https://") {
driverConfig.CoreConfig.Log.Printf("Malformed Acr repository. https:// required. Refusing to continue.\n")
return errors.New("malformed acr repository - https:// required")
}

if pluginToolConfig["trcplugin"] != nil && len(pluginToolConfig["trcplugin"].(string)) == 0 {
driverConfig.CoreConfig.Log.Printf("Trcplugin undefined. Refusing to continue.\n")
return errors.New("undefined trcplugin")
}

return nil
}