rightsStr = new ArrayList<>();
- for (com.microsoft.azure.management.eventhub.AccessRights rights : resource.rights()) {
- rightsStr.add(rights.toString());
- }
- info.append("\n\tRights: ").append(rightsStr);
- System.out.println(info.toString());
- }
-
- /**
- * Print event hub namespace recovery pairing auth rule key.
- *
- * @param resource event hub namespace disaster recovery pairing auth rule key
- */
- public static void print(DisasterRecoveryPairingAuthorizationKey resource) {
- StringBuilder info = new StringBuilder();
- info.append("DisasterRecoveryPairing auth key: ")
- .append("\n\t Alias primary connection string: ").append(resource.aliasPrimaryConnectionString())
- .append("\n\t Alias secondary connection string: ").append(resource.aliasSecondaryConnectionString())
- .append("\n\t Primary key: ").append(resource.primaryKey())
- .append("\n\t Secondary key: ").append(resource.secondaryKey())
- .append("\n\t Primary connection string: ").append(resource.primaryConnectionString())
- .append("\n\t Secondary connection string: ").append(resource.secondaryConnectionString());
- System.out.println(info.toString());
- }
-
- /**
- * Print event hub consumer group.
- *
- * @param resource event hub consumer group
- */
- public static void print(EventHubConsumerGroup resource) {
- StringBuilder info = new StringBuilder();
- info.append("Event hub consumer group: ").append(resource.id())
- .append("\n\tName: ").append(resource.name())
- .append("\n\tNamespace resource group: ").append(resource.namespaceResourceGroupName())
- .append("\n\tNamespace: ").append(resource.namespaceName())
- .append("\n\tEvent hub name: ").append(resource.eventHubName())
- .append("\n\tUser metadata: ").append(resource.userMetadata());
- System.out.println(info.toString());
- }
-
- /**
- * Print Batch AI Cluster.
- *
- * @param resource batch ai cluster
- */
- public static void print(BatchAICluster resource) {
- StringBuilder info = new StringBuilder("Batch AI cluster: ")
- .append("\n\tId: ").append(resource.id())
- .append("\n\tName: ").append(resource.name())
- .append("\n\tResource group: ").append(resource.workspace().resourceGroupName())
- .append("\n\tRegion: ").append(resource.workspace().regionName())
- .append("\n\tVM Size: ").append(resource.vmSize())
- .append("\n\tVM Priority: ").append(resource.vmPriority())
- .append("\n\tSubnet: ").append(resource.subnet())
- .append("\n\tAllocation state: ").append(resource.allocationState())
- .append("\n\tAllocation state transition time: ").append(resource.allocationStateTransitionTime())
- .append("\n\tCreation time: ").append(resource.creationTime())
- .append("\n\tCurrent node count: ").append(resource.currentNodeCount())
- .append("\n\tAllocation state transition time: ").append(resource.allocationStateTransitionTime())
- .append("\n\tAllocation state transition time: ").append(resource.allocationStateTransitionTime());
- if (resource.scaleSettings().autoScale() != null) {
- info.append("\n\tAuto scale settings: ")
- .append("\n\t\tInitial node count: ").append(resource.scaleSettings().autoScale().initialNodeCount())
- .append("\n\t\tMinimum node count: ").append(resource.scaleSettings().autoScale().minimumNodeCount())
- .append("\n\t\tMaximum node count: ").append(resource.scaleSettings().autoScale().maximumNodeCount());
- }
- if (resource.scaleSettings().manual() != null) {
- info.append("\n\tManual scale settings: ")
- .append("\n\t\tTarget node count: ").append(resource.scaleSettings().manual().targetNodeCount())
- .append("\n\t\tDeallocation option: ")
- .append(resource.scaleSettings().manual().nodeDeallocationOption());
- }
- if (resource.nodeStateCounts() != null) {
- info.append("\n\tNode state counts: ")
- .append("\n\t\tRunning nodes count: ").append(resource.nodeStateCounts().runningNodeCount())
- .append("\n\t\tIdle nodes count: ").append(resource.nodeStateCounts().idleNodeCount())
- .append("\n\t\tPreparing nodes count: ").append(resource.nodeStateCounts().preparingNodeCount())
- .append("\n\t\tLeaving nodes count: ").append(resource.nodeStateCounts().leavingNodeCount())
- .append("\n\t\tPreparing nodes count: ").append(resource.nodeStateCounts().preparingNodeCount());
- }
- if (resource.virtualMachineConfiguration() != null && resource.virtualMachineConfiguration().imageReference() != null) {
- info.append("\n\tVirtual machine configuration: ")
- .append("\n\t\tPublisher: ").append(resource.virtualMachineConfiguration().imageReference().publisher())
- .append("\n\t\tOffer: ").append(resource.virtualMachineConfiguration().imageReference().offer())
- .append("\n\t\tSku: ").append(resource.virtualMachineConfiguration().imageReference().sku())
- .append("\n\t\tVersion: ").append(resource.virtualMachineConfiguration().imageReference().version());
- }
- if (resource.nodeSetup() != null && resource.nodeSetup().setupTask() != null) {
- info.append("\n\tSetup task: ")
- .append("\n\t\tCommand line: ").append(resource.nodeSetup().setupTask().commandLine())
- .append("\n\t\tStdout/err Path Prefix: ").append(resource.nodeSetup().setupTask().stdOutErrPathPrefix());
- }
- System.out.println(info.toString());
- }
-
- /**
- * Print Batch AI Job.
- *
- * @param resource batch ai job
- */
- public static void print(BatchAIJob resource) {
- StringBuilder info = new StringBuilder("Batch AI job: ")
- .append("\n\tId: ").append(resource.id())
- .append("\n\tName: ").append(resource.name())
- .append("\n\tCluster Id: ").append(resource.cluster())
- .append("\n\tCreation time: ").append(resource.creationTime())
- .append("\n\tNode count: ").append(resource.nodeCount())
- .append("\n\tPriority: ").append(resource.schedulingPriority())
- .append("\n\tExecution state: ").append(resource.executionState())
- .append("\n\tExecution state transition time: ").append(resource.executionStateTransitionTime())
- .append("\n\tTool type: ").append(resource.toolType())
- .append("\n\tExperiment name: ").append(resource.experiment().name());
- if (resource.mountVolumes() != null) {
- info.append("\n\tMount volumes:");
- if (resource.mountVolumes().azureFileShares() != null) {
- info.append("\n\t\tAzure fileshares:");
- for (AzureFileShareReference share : resource.mountVolumes().azureFileShares()) {
- info.append("\n\t\t\tAccount name:").append(share.accountName())
- .append("\n\t\t\tFile Url:").append(share.azureFileUrl())
- .append("\n\t\t\tDirectory mode:").append(share.directoryMode())
- .append("\n\t\t\tFile mode:").append(share.fileMode())
- .append("\n\t\t\tRelative mount path:").append(share.relativeMountPath());
- }
- }
- }
- System.out.println(info.toString());
- }
/**
* Print Diagnostic Setting.
@@ -3125,32 +3194,209 @@ public static void print(MetricAlert metricAlert) {
}
System.out.println(info.toString());
}
- private static OkHttpClient httpClient;
- /**
- * Ensure the HTTP client is valid.
+// /**
+// * Print spring service settings.
+// *
+// * @param springService spring service instance
+// */
+// public static void print(SpringService springService) {
+// StringBuilder info = new StringBuilder("Spring Service: ")
+// .append("\n\tId: ").append(springService.id())
+// .append("\n\tName: ").append(springService.name())
+// .append("\n\tResource Group: ").append(springService.resourceGroupName())
+// .append("\n\tRegion: ").append(springService.region())
+// .append("\n\tTags: ").append(springService.tags());
+//
+// ConfigServerProperties serverProperties = springService.getServerProperties();
+// if (serverProperties != null && serverProperties.provisioningState() != null
+// && serverProperties.provisioningState().equals(ConfigServerState.SUCCEEDED) && serverProperties.configServer() != null) {
+// info.append("\n\tProperties: ");
+// if (serverProperties.configServer().gitProperty() != null) {
+// info.append("\n\t\tGit: ").append(serverProperties.configServer().gitProperty().uri());
+// }
+// }
+//
+// if (springService.sku() != null) {
+// info.append("\n\tSku: ")
+// .append("\n\t\tName: ").append(springService.sku().name())
+// .append("\n\t\tTier: ").append(springService.sku().tier())
+// .append("\n\t\tCapacity: ").append(springService.sku().capacity());
+// }
+//
+// MonitoringSettingProperties monitoringSettingProperties = springService.getMonitoringSetting();
+// if (monitoringSettingProperties != null && monitoringSettingProperties.provisioningState() != null
+// && monitoringSettingProperties.provisioningState().equals(MonitoringSettingState.SUCCEEDED)) {
+// info.append("\n\tTrace: ")
+// .append("\n\t\tEnabled: ").append(monitoringSettingProperties.traceEnabled())
+// .append("\n\t\tApp Insight Instrumentation Key: ").append(monitoringSettingProperties.appInsightsInstrumentationKey());
+// }
+//
+// System.out.println(info.toString());
+// }
+//
+// /**
+// * Print spring app settings.
+// *
+// * @param springApp spring app instance
+// */
+// public static void print(SpringApp springApp) {
+// StringBuilder info = new StringBuilder("Spring Service: ")
+// .append("\n\tId: ").append(springApp.id())
+// .append("\n\tName: ").append(springApp.name())
+// .append("\n\tCreated Time: ").append(springApp.createdTime())
+// .append("\n\tPublic Endpoint: ").append(springApp.isPublic())
+// .append("\n\tUrl: ").append(springApp.url())
+// .append("\n\tHttps Only: ").append(springApp.isHttpsOnly())
+// .append("\n\tFully Qualified Domain Name: ").append(springApp.fqdn())
+// .append("\n\tActive Deployment Name: ").append(springApp.activeDeploymentName());
+//
+// if (springApp.temporaryDisk() != null) {
+// info.append("\n\tTemporary Disk:")
+// .append("\n\t\tSize In GB: ").append(springApp.temporaryDisk().sizeInGB())
+// .append("\n\t\tMount Path: ").append(springApp.temporaryDisk().mountPath());
+// }
+//
+// if (springApp.persistentDisk() != null) {
+// info.append("\n\tPersistent Disk:")
+// .append("\n\t\tSize In GB: ").append(springApp.persistentDisk().sizeInGB())
+// .append("\n\t\tMount Path: ").append(springApp.persistentDisk().mountPath());
+// }
+//
+// if (springApp.identity() != null) {
+// info.append("\n\tIdentity:")
+// .append("\n\t\tType: ").append(springApp.identity().type())
+// .append("\n\t\tPrincipal Id: ").append(springApp.identity().principalId())
+// .append("\n\t\tTenant Id: ").append(springApp.identity().tenantId());
+// }
+//
+// System.out.println(info.toString());
+// }
+
+ /**
+ * Sends a GET request to target URL.
+ *
+ * Retry logic tuned for AppService.
+ * The method does not handle 301 redirect.
*
+ * @param urlString the target URL.
+ * @return Content of the HTTP response.
*/
- private static OkHttpClient ensureValidHttpClient() {
- if (httpClient == null) {
- httpClient = new OkHttpClient.Builder().readTimeout(1, TimeUnit.MINUTES).build();
- }
+ public static String sendGetRequest(String urlString) {
+ ClientLogger logger = new ClientLogger(Utils.class);
- return httpClient;
+ try {
+ Mono>> response =
+ HTTP_CLIENT.getString(getHost(urlString), getPathAndQuery(urlString))
+ .retryWhen(Retry
+ .fixedDelay(5, Duration.ofSeconds(30))
+ .filter(t -> {
+ boolean retry = false;
+ if (t instanceof TimeoutException) {
+ retry = true;
+ } else if (t instanceof HttpResponseException
+ && ((HttpResponseException) t).getResponse().getStatusCode() == 503) {
+ retry = true;
+ }
+
+ if (retry) {
+ logger.info("retry GET request to {}", urlString);
+ }
+ return retry;
+ }));
+ Response ret = stringResponse(response).block();
+ return ret == null ? null : ret.getValue();
+ } catch (MalformedURLException e) {
+ logger.logThrowableAsError(e);
+ return null;
+ }
}
/**
- * Connect to a specified URL using "curl" like HTTP GET client.
+ * Sends a POST request to target URL.
+ *
+ * Retry logic tuned for AppService.
*
- * @param url URL to be tested
- * @return the HTTP GET response content
- */
- public static String curl(String url) {
- Request request = new Request.Builder().url(url).get().build();
+ * @param urlString the target URL.
+ * @param body the request body.
+ * @return Content of the HTTP response.
+ * */
+ public static String sendPostRequest(String urlString, String body) {
+ ClientLogger logger = new ClientLogger(Utils.class);
+
try {
- return ensureValidHttpClient().newCall(request).execute().body().string();
- } catch (IOException e) {
+ Mono> response =
+ stringResponse(HTTP_CLIENT.postString(getHost(urlString), getPathAndQuery(urlString), body))
+ .retryWhen(Retry
+ .fixedDelay(5, Duration.ofSeconds(30))
+ .filter(t -> {
+ boolean retry = false;
+ if (t instanceof TimeoutException) {
+ retry = true;
+ }
+
+ if (retry) {
+ logger.info("retry POST request to {}", urlString);
+ }
+ return retry;
+ }));
+ Response ret = response.block();
+ return ret == null ? null : ret.getValue();
+ } catch (Exception e) {
+ logger.logThrowableAsError(e);
return null;
}
}
+
+ private static Mono> stringResponse(Mono>> responseMono) {
+ return responseMono.flatMap(response -> FluxUtil.collectBytesInByteBufferStream(response.getValue())
+ .map(bytes -> new String(bytes, StandardCharsets.UTF_8))
+ .map(str -> new SimpleResponse<>(response.getRequest(), response.getStatusCode(), response.getHeaders(), str)));
+ }
+
+ private static String getHost(String urlString) throws MalformedURLException {
+ URL url = new URL(urlString);
+ String protocol = url.getProtocol();
+ String host = url.getAuthority();
+ return protocol + "://" + host;
+ }
+
+ private static String getPathAndQuery(String urlString) throws MalformedURLException {
+ URL url = new URL(urlString);
+ String path = url.getPath();
+ String query = url.getQuery();
+ if (query != null && !query.isEmpty()) {
+ path = path + "?" + query;
+ }
+ return path;
+ }
+
+ private static final WebAppTestClient HTTP_CLIENT = RestProxy.create(
+ WebAppTestClient.class,
+ new HttpPipelineBuilder()
+ .policies(
+ new HttpLoggingPolicy(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BASIC)),
+ new RetryPolicy("Retry-After", ChronoUnit.SECONDS))
+ .build());
+
+ @Host("{$host}")
+ @ServiceInterface(name = "WebAppTestClient")
+ private interface WebAppTestClient {
+ @Get("{path}")
+ @ExpectedResponses({200, 400, 404})
+ Mono>> getString(@HostParam("$host") String host, @PathParam(value = "path", encoded = true) String path);
+
+ @Post("{path}")
+ @ExpectedResponses({200, 400, 404})
+ Mono>> postString(@HostParam("$host") String host, @PathParam(value = "path", encoded = true) String path, @BodyParam("text/plain") String body);
+ }
+
+ public static int getSize(Iterable iterable) {
+ int res = 0;
+ Iterator iterator = iterable.iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ }
+ return res;
+ }
}
diff --git a/src/main/java/com/microsoft/azure/management/appservice/samples/ManageFunctionAppLogs.java b/src/main/java/com/microsoft/azure/management/appservice/samples/ManageFunctionAppLogs.java
deleted file mode 100644
index 27d2876..0000000
--- a/src/main/java/com/microsoft/azure/management/appservice/samples/ManageFunctionAppLogs.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/**
- * 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.management.appservice.samples;
-
-import com.microsoft.azure.management.Azure;
-import com.microsoft.azure.management.appservice.FunctionApp;
-import com.microsoft.azure.management.resources.fluentcore.arm.Region;
-import com.microsoft.azure.management.resources.fluentcore.utils.SdkContext;
-import com.microsoft.azure.management.samples.Utils;
-import com.microsoft.rest.LogLevel;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import org.apache.commons.lang3.time.StopWatch;
-import rx.Subscriber;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Azure App Service basic sample for managing function apps.
- * - Create a function app under the same new app service plan:
- * - Deploy to app using FTP
- * - stream logs synchronously for 30 seconds
- * - stream logs asynchronously until 3 requests are completed
- */
-public final class ManageFunctionAppLogs {
-
- private static OkHttpClient httpClient;
-
- /**
- * Main function which runs the actual sample.
- * @param azure instance of the azure client
- * @return true if sample runs successfully
- */
- public static boolean runSample(Azure azure) {
- // New resources
- final String suffix = ".azurewebsites.net";
- final String appName = SdkContext.randomResourceName("webapp1-", 20);
- final String appUrl = appName + suffix;
- final String rgName = SdkContext.randomResourceName("rg1NEMV_", 24);
-
- try {
-
-
- //============================================================
- // Create a function app with a new app service plan
-
- System.out.println("Creating function app " + appName + " in resource group " + rgName + "...");
-
- FunctionApp app = azure.appServices().functionApps().define(appName)
- .withRegion(Region.US_WEST)
- .withNewResourceGroup(rgName)
- .defineDiagnosticLogsConfiguration()
- .withApplicationLogging()
- .withLogLevel(com.microsoft.azure.management.appservice.LogLevel.VERBOSE)
- .withApplicationLogsStoredOnFileSystem()
- .attach()
- .create();
-
- System.out.println("Created function app " + app.name());
- Utils.print(app);
-
- //============================================================
- // Deploy to app 1 through FTP
-
- System.out.println("Deploying a function app to " + appName + " through FTP...");
-
- Utils.uploadFileToFunctionApp(app.getPublishingProfile(), "host.json", ManageFunctionAppLogs.class.getResourceAsStream("/square-function-app/host.json"));
- Utils.uploadFileToFunctionApp(app.getPublishingProfile(), "square/function.json", ManageFunctionAppLogs.class.getResourceAsStream("/square-function-app/square/function.json"));
- Utils.uploadFileToFunctionApp(app.getPublishingProfile(), "square/index.js", ManageFunctionAppLogs.class.getResourceAsStream("/square-function-app/square/index.js"));
-
- // sync triggers
- app.syncTriggers();
-
- System.out.println("Deployment square app to function app " + app.name() + " completed");
- Utils.print(app);
-
- // warm up
- System.out.println("Warming up " + appUrl + "/api/square...");
- post("http://" + appUrl + "/api/square", "625");
- SdkContext.sleep(5000);
-
- //============================================================
- // Listen to logs synchronously for 30 seconds
-
- final InputStream stream = app.streamApplicationLogs();
- System.out.println("Streaming logs from function app " + appName + "...");
- String line = readLine(stream);
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- new Thread(new Runnable() {
- @Override
- public void run() {
- post("http://" + appUrl + "/api/square", "625");
- SdkContext.sleep(10000);
- post("http://" + appUrl + "/api/square", "725");
- SdkContext.sleep(10000);
- post("http://" + appUrl + "/api/square", "825");
- }
- }).start();
- while (line != null && stopWatch.getTime() < 90000) {
- System.out.println(line);
- line = readLine(stream);
- }
- stream.close();
-
- //============================================================
- // Listen to logs asynchronously until 3 requests are completed
-
- new Thread(new Runnable() {
- @Override
- public void run() {
- SdkContext.sleep(5000);
- System.out.println("Starting hitting");
- post("http://" + appUrl + "/api/square", "625");
- SdkContext.sleep(10000);
- post("http://" + appUrl + "/api/square", "725");
- SdkContext.sleep(10000);
- post("http://" + appUrl + "/api/square", "825");
- }
- }).start();
-
- final AtomicInteger count = new AtomicInteger(0);
- app.streamApplicationLogsAsync()
- .subscribe(new Subscriber() {
- @Override
- public void onCompleted() {
- // automatically unsubscribe
- }
-
- @Override
- public void onError(Throwable e) {
- e.printStackTrace();
- }
-
- @Override
- public void onNext(String s) {
- System.out.println(s);
- if (s.contains("Function completed")) {
- if (count.incrementAndGet() >= 3) {
- unsubscribe();
- }
- }
- }
- });
-
- return true;
- } catch (Exception e) {
- System.err.println(e.getMessage());
- e.printStackTrace();
- } finally {
- try {
- System.out.println("Deleting Resource Group: " + rgName);
- azure.resourceGroups().beginDeleteByName(rgName);
- System.out.println("Deleted Resource Group: " + rgName);
- } catch (NullPointerException npe) {
- System.out.println("Did not create any resources in Azure. No clean up is necessary");
- } catch (Exception g) {
- g.printStackTrace();
- }
- }
- return false;
- }
- /**
- * Main entry point.
- * @param args the parameters
- */
- public static void main(String[] args) {
- try {
-
- //=============================================================
- // Authenticate
-
- final File credFile = new File(System.getenv("AZURE_AUTH_LOCATION"));
-
- Azure azure = Azure
- .configure()
- .withLogLevel(LogLevel.BASIC)
- .authenticate(credFile)
- .withDefaultSubscription();
-
- // Print selected subscription
- System.out.println("Selected subscription: " + azure.subscriptionId());
-
- runSample(azure);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- e.printStackTrace();
- }
- }
-
- private static String curl(String url) {
- Request request = new Request.Builder().url(url).get().build();
- try {
- return httpClient.newCall(request).execute().body().string();
- } catch (IOException e) {
- return null;
- }
- }
-
- private static String post(String url, String body) {
- Request request = new Request.Builder().url(url).post(RequestBody.create(MediaType.parse("text/plain"), body)).build();
- try {
- return httpClient.newCall(request).execute().body().string();
- } catch (IOException e) {
- return null;
- }
- }
-
- private static String readLine(InputStream in) throws IOException {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- int c;
- for (c = in.read(); c != '\n' && c >= 0; c = in.read()) {
- stream.write(c);
- }
- if (c == -1 && stream.size() == 0) {
- return null;
- }
- return stream.toString("UTF-8");
- }
-
- static {
- httpClient = new OkHttpClient.Builder().readTimeout(1, TimeUnit.MINUTES).build();
- }
-}