All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.azure.toolkit.lib.containerregistry.ContainerRegistry Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 */

package com.microsoft.azure.toolkit.lib.containerregistry;

import com.azure.core.util.BinaryData;
import com.azure.resourcemanager.containerregistry.ContainerRegistryManager;
import com.azure.resourcemanager.containerregistry.fluent.models.RegistryInner;
import com.azure.resourcemanager.containerregistry.models.AccessKeyType;
import com.azure.resourcemanager.containerregistry.models.ImageDescriptor;
import com.azure.resourcemanager.containerregistry.models.ProvisioningState;
import com.azure.resourcemanager.containerregistry.models.PublicNetworkAccess;
import com.azure.resourcemanager.containerregistry.models.Registry;
import com.azure.resourcemanager.containerregistry.models.RegistryTaskRun;
import com.azure.resourcemanager.containerregistry.models.RunStatus;
import com.azure.resourcemanager.containerregistry.models.SourceUploadDefinition;
import com.azure.resourcemanager.resources.fluentcore.utils.ResourceManagerUtils;
import com.azure.storage.blob.specialized.BlockBlobClient;
import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder;
import com.google.common.collect.ImmutableSet;
import com.microsoft.azure.toolkit.lib.common.action.Action;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.exception.StreamingDiagnosticsException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResourceModule;
import com.microsoft.azure.toolkit.lib.common.model.Region;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.utils.StreamingLogSupport;
import com.microsoft.azure.toolkit.lib.containerregistry.model.Sku;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

public class ContainerRegistry extends AbstractAzResource {
    public static final String ACR_IMAGE_SUFFIX = ".azurecr.io";
    @Getter
    private final RepositoryModule repositoryModule;

    protected ContainerRegistry(@Nonnull String name, @Nonnull String resourceGroupName, @Nonnull AzureContainerRegistryModule module) {
        super(name, resourceGroupName, module);
        this.repositoryModule = new RepositoryModule(this);
    }

    protected ContainerRegistry(@Nonnull ContainerRegistry registry) {
        super(registry);
        this.repositoryModule = registry.repositoryModule;
    }

    protected ContainerRegistry(@Nonnull Registry registry, @Nonnull AzureContainerRegistryModule module) {
        super(registry.name(), registry.resourceGroupName(), module);
        this.repositoryModule = new RepositoryModule(this);
    }

    @Nonnull
    @Override
    public List> getSubModules() {
        return Collections.singletonList(this.repositoryModule);
    }

    @Nonnull
    @Override
    protected String loadStatus(@Nonnull Registry remote) {
        return Optional.ofNullable(remote.innerModel()).map(RegistryInner::provisioningState).map(ProvisioningState::toString).orElse(Status.UNKNOWN);
    }

    public boolean isAdminUserEnabled() {
        return remoteOptional().map(Registry::adminUserEnabled).orElse(false);
    }

    public boolean isPublicAccessEnabled() {
        return remoteOptional().map(r -> r.publicNetworkAccess() == PublicNetworkAccess.ENABLED).orElse(true);
    }

    @AzureOperation(name = "internal/acr.enable_admin_user.registry", params = "this.getName()")
    public void enableAdminUser() {
        ContainerRegistryDraft update = (ContainerRegistryDraft) this.update();
        update.setAdminUserEnabled(true);
        update.commit();
    }

    @AzureOperation(name = "internal/acr.disable_admin_user.registry", params = "this.getName()")
    public void disableAdminUser() {
        ContainerRegistryDraft update = (ContainerRegistryDraft) this.update();
        update.setAdminUserEnabled(false);
        update.commit();
    }

    @Nullable
    public Sku getSku() {
        return remoteOptional().map(Registry::sku).map(sku -> sku.tier().toString()).map(Sku::valueOf).orElse(null);
    }

    @Nullable
    public Region getRegion() {
        return remoteOptional().map(registry -> registry.region().name()).map(Region::fromName).orElse(null);
    }

    @Nullable
    public String getUserName() {
        return remoteOptional().map(registry -> registry.getCredentials().username()).orElse(null);
    }

    @Nullable
    public String getPrimaryCredential() {
        return remoteOptional().map(registry -> registry.getCredentials().accessKeys())
            .map(map -> map.get(AccessKeyType.PRIMARY)).orElse(null);
    }

    @Nullable
    public String getSecondaryCredential() {
        return remoteOptional().map(registry -> registry.getCredentials().accessKeys())
            .map(map -> map.get(AccessKeyType.SECONDARY)).orElse(null);
    }

    @Nullable
    public String getLoginServerUrl() {
        return remoteOptional().map(Registry::loginServerUrl).orElse(null);
    }

    @Nullable
    public String getType() {
        return remoteOptional().map(Registry::type).orElse(null);
    }

    /**
     * @return image build task run, null if registry is not ready
     */
    @Nullable
    public RegistryTaskRun buildImage(final String imageNameWithTag, final Path sourceTar) {
        return this.remoteOptional().map(r -> {
            // upload tar.gz file
            AzureMessager.getMessager().progress(AzureString.format("Uploading compressed source code to Registry '%s'.", this.getName()));
            final SourceUploadDefinition upload = r.getBuildSourceUploadUrl();
            final BlockBlobClient blobClient = new SpecializedBlobClientBuilder().endpoint(upload.uploadUrl()).buildBlockBlobClient();
            blobClient.upload(BinaryData.fromFile(sourceTar));

            AzureMessager.getMessager().progress(AzureString.format("Building image '%s' in Registry '%s'.", imageNameWithTag, this.getName()));
            return r.scheduleRun().withLinux().withDockerTaskRunRequest()
                .defineDockerTaskStep()
                .withDockerFilePath("./Dockerfile")
                .withImageNames(Collections.singletonList(imageNameWithTag))
                .withPushEnabled(true)
                .attach()
                .withSourceLocation(upload.relativePath())
                .execute();
        }).orElse(null);
    }

    @Nullable
    public String waitForImageBuilding(@Nonnull final RegistryTaskRun run) {
        final ImmutableSet errorStatus = ImmutableSet.of(RunStatus.FAILED, RunStatus.CANCELED, RunStatus.ERROR, RunStatus.TIMEOUT);
        final ImmutableSet waitingStatus = ImmutableSet.of(RunStatus.QUEUED, RunStatus.STARTED, RunStatus.RUNNING);

        final ContainerRegistryManager registryManager = Objects.requireNonNull(this.getParent().getRemote());
        String logSasUrl = registryManager.registryTaskRuns().getLogSasUrl(this.getResourceGroupName(), this.getName(), run.runId());
        if (!logSasUrl.startsWith("https://") && !logSasUrl.startsWith("http://")) {
            logSasUrl = "https://" + logSasUrl;
        }
        final Action openUrl = AzureActionManager.getInstance().getAction(Action.OPEN_URL);
        final Action viewLogInBrowser = openUrl.bind(logSasUrl).withLabel("Open streaming logs in browser");
        final RegistryTaskRunStreamingLog urlStreamingLog = RegistryTaskRunStreamingLog.builder().logSasUrl(logSasUrl).task(run).build();
        final Action viewLogInToolkit = AzureActionManager.getInstance().getAction(StreamingLogSupport.OPEN_STREAMING_LOG)
            .bind(urlStreamingLog).withLabel("Open streaming logs");
        AzureMessager.getMessager().info(AzureString.format("Waiting for image building task run (%s) to be completed...", run.runId()), viewLogInToolkit, viewLogInBrowser);
        RunStatus status = run.status();
        while (waitingStatus.contains(status)) {
            ResourceManagerUtils.sleep(Duration.ofSeconds(10));
            run.refresh();
            status = run.status();
        }
        final List images = run.innerModel().outputImages();
        if (errorStatus.contains(status) || CollectionUtils.isEmpty(images)) {
            final String message = String.format("Failed to build image (status: %s). View logs at %s for more details.", status, logSasUrl);
            throw new StreamingDiagnosticsException(message, urlStreamingLog);
        }
        final ImageDescriptor image = images.get(0);
        final String fullImageName = String.format("%s/%s:%s", image.registry(), image.repository(), image.tag());
        AzureMessager.getMessager().info(AzureString.format("Image building task run %s is completed successfully, image %s is built.", run.runId(), fullImageName), viewLogInToolkit, viewLogInBrowser);
        // refresh to load newly build images.
        this.refresh();
        ResourceManagerUtils.sleep(Duration.ofSeconds(3));
        return fullImageName;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy