How do I start a previously stopped Azure Container instance using C#? - c#

I have the following code to stop an Azure container instance and would like to start it using similar.
using Microsoft.Azure.Management.Compute.Fluent.Models;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal("XXXX", "XXXX", "XXXX", AzureEnvironment.AzureGlobalCloud);
var azure = Azure
.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(credentials)
.WithSubscription("XXXXX");
var containerName = "mycontainer";
var containerGroup = azure.ContainerGroups.GetByResourceGroup("myResourceGroup", containerName);
if (containerGroup.State == "Running")
{
containerGroup.Stop();
}
I would like to do the same and start my azure container instance. So where is containerGroup.Start(); ? This does not appear to exist in the interface. I have tried using containerGroup.Restart(); but this does not work from a stopped state. I need to be able to do this from within C# code and would like to avoid powershell if possible.

There is a way to do this but it is not exposed in the fluent API:
using Microsoft.Azure.Management.ContainerInstance.Fluent;
// azure is an instance of IAzure; the fluent Azure API
var resources = await azure.ContainerGroups.ListAsync();
foreach(var containerGroup in resources.Where(aci => aci.State != "Running"))
{
await ContainerGroupsOperationsExtensions.StartAsync(
containerGroup.Manager.Inner.ContainerGroups,
containerGroup.ResourceGroupName,
containerGroup.Name);
}
As mentioned by other people, you do need to realize that this is effectively starting a fresh container. No state will be maintained from the previous run unless you persisted that somewhere else like in a mounted volume.
You'll also need to grant the appropriate rights to whom ever is executing this code. I'm using a function so I had to setup a service account and a role, this blog post has all the details.
Update
The code I'm using is in on GitHub: https://github.com/alanta/azure_scheduler/blob/master/src/StartACIs.cs

Unfortunately, when you stop the container instances, they would be in the Terminated state and you cannot start them again.
Terminated or deleted container groups can't be updated. Once a
container group has stopped (is in the Terminated state) or has been
deleted, the group is deployed as new.
Even if you update the ACI, it also means the ACI would be redeployed. You can take a look at Update containers in Azure Container Instances. In addition, the Restart action also works when the container instances are in the running state.
So there is no start function in the C# SDK for you, at least now. Hope this will help you.
Update
Take a look at the event:
Each time when you start the container group after stop, the container group always these steps: pull the image -> create the container group -> start the container instances. So it’s clear, the container group was recreated when you start it after stop.

Related

Link event to dependency?

I'm using TelemetryClient.TrackEvent to record file uploads within my .NET Core/C# web service, with their duration and throughput.
I'm also using DependencyTelemetry to connect together the various stages of my event handling:
using var dop = TelemetryClient.StartOperation<DependencyTelemetry>("Upload file event", correlationId);
However I don't see a way to connect the custom event to the dependency, so it shows up in the Application Insights Performance page. I see my request and the child dependencies, but no custom events. It would be great to see the custom events spawned from within my dependency, all linked together.
Is this possible?
Figured this out, and now I'm getting traces linked to requests/dependencies. Also showing how to set a custom role name on the TelemetryClient.
var tconfiguration = new TelemetryConfiguration
{
InstrumentationKey = Configuration.GetSection("ApplicationInsights")?["InstrumentationKey"]
};
tconfiguration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
this.TelemetryClient = new TelemetryClient(tconfiguration);
TelemetryClient.Context.Cloud.RoleName = Configuration.GetSection("ApplicationInsights")?["RoleName"];

Botframework How to change table storage connection string in startup based on incomming request

I'm using BotFramework version(v4) integrated with LUIS. In ConfigureServices(IServiceCollection services) method in startup.cs file I'm assigning storage and LUIS in the middleware.Below is the sample code.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(configuration);
services.AddBot<ChoiceBot>(options =>
{
options.CredentialProvider = new ConfigurationCredentialProvider(configuration);
var (luisModelId, luisSubscriptionKey, luisUri) = GetLuisConfiguration(configuration, "TestBot_Dispatch");//
var luisModel = new LuisModel(luisModelId, luisSubscriptionKey, luisUri);
var luisOptions = new LuisRequest { Verbose = true };
options.Middleware.Add(new LuisRecognizerMiddleware(luisModel, luisOptions: luisOptions));
//azure storage emulater
//options.Middleware.Add(new ConversationState<Dictionary<string, object>>(new AzureTableStorage("UseDevelopmentStorage=true", "conversationstatetable")));
IStorage dataStore = new AzureTableStorage("DefaultEndpointsProtocol=https;AccountName=chxxxxxx;AccountKey=xxxxxxxxx;EndpointSuffix=core.windows.net", "TableName");
options.Middleware.Add(new ConversationState<Dictionary<string,object>>(new MemoryStorage()));
options.Middleware.Add(new UserState<UserStateStorage>(dataStore));
}
}
My bot will be getting requests from users of different roles such as (admin,sales,etc..).I want to change the table storage connection-string passed to middleware based on the role extracted from the incoming request. I will get user role by querying DB from the user-name which is extracted from the current TurnContext object of an incoming request. I'm able to do this in OnTurn method, but as these are already declared in middleware I wanted to change them while initializing in the middleware itself.
In .NET Core, Startup logic is only executed once at, er, startup.😊
If I understand you correctly, what you need to be able to do is: at runtime, switch between multiple storage providers that, in your case, are differentiated by their underlying connection string.
There is nothing "in the box" that enables this scenario for you, but it is possible if use the correct extension points and write the correct plumbing for yourself. Specifically you can provide a customized abstraction at the IStatePropertyAccessor<T> layer and your upstream code would continue to work at that level abstraction and be none-the-wiser.
Here's an implementation I've started that includes something I'm calling the ConditionalStatePropertyAccessor. It allows you to create a sort of composite IStatePropertyAccessor<T> that is configured with both a default/fallback instance as well as N other instances that are supplied with a selector function that allows them to look at the incoming ITurnContext and, based on some details from any part of the turn, indicate that that's the instance that should be used for the scope of the turn. Take a look at the tests and you can see how I configure a sample that chooses an implementation based on the ChannelId for example.
I am a little busy at the moment and can't ship this right now, but I intend to package it up and ship it eventually. However, if you think it would be helpful, please feel free to just copy the code for your own use. 👍

Using SqlBotDataStore for bot state falls back instead to state.botframework.com

I'm using the Nuget Microsoft.Bot.Builder.Azure package extensions to store my bot's state. BotBuilder 3.14.0, Bot.Builder.Azure 3.2.5.
I've been successfully using TableBotDataStore up until now, using Azure table storage. On starting a conversation, I can immediately inspect the table and see relevant rows created in it.
I tried using SqlBotDataStore, having run the script to create the table in my (Azure) SQL Server DB. I registered it as per the sample code, but on redeployment I find that, although no errors are thrown, no entries are created in the SqlBotDataEntities table, and instead state.botframework.com is being called as part of the request dependencies.
var sqlStore = new SqlBotDataStore(ConfigurationManager.
ConnectionStrings["SqlBotStorage"].ConnectionString);
builder.Register(c => sqlStore)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
has replaced the (working)
var azureTableStore = new TableBotDataStore(
ConfigurationManager.ConnectionStrings["TableStorageCS"].ConnectionString,
sBotStorageTableName);
builder.Register(c => azureTableStore)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
builder.Register(c => new CachingBotDataStore(azureTableStore,
CachingBotDataStoreConsistencyPolicy
.ETagBasedConsistency))
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
I know the connection string is kosher, as I tried a test in a dummy action method:
IBotDataStore<BotData> sqlds = new SqlBotDataStore(
ConfigurationManager.ConnectionStrings["SqlBotStorage"].ConnectionString);
var key = new Address("botidhere", "effbee", "uid1", "c1", "x.com");
var bd = new BotData(data: new Dialogs.SimpleResponseDialog("message here"));
await sqlds.SaveAsync(key, BotStoreType.BotUserData, bd, default(CancellationToken));
and that adds a row just fine.
What else am I missing? The relevant connection string is stored in Azure application settings, as a connection string of type 'SQLAzure':
Server=tcp:xxxx.database.windows.net;Initial Catalog=xxxx;Persist Security Info=False;User ID=xxxx;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
I appear* to have fixed it - I was missing the AzureModule registration line:
builder.RegisterModule(new AzureModule(System.Reflection.Assembly.GetExecutingAssembly()));
Here's the thing though - this wasn't needed for using TableBotDataStore. Only SqlBotDataStore.
Another thing: adding the line fixed the issue immediately in an Azure deployment slot with a debug build, system.debug=true. However, deploying to the main webapp (non-slot) with a release build, system.debug=false caused the app to be unable to start. '503 Service Unavailable'. No logs. Reverting immediately to table storage and all was well again.
I'm currently try..catching the above line, but I can't see an exception thrown, yet it has started working now. One to keep an eye on!
*with caveats above...

How to make startup Azure Function

I have a Azure Function like that
[FunctionName("Function1")]
public static void Run([ServiceBusTrigger("myqueue", AccessRights.Manage, Connection = "AzureWebJobsServiceBus")]string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
I want to dynamic bind myqueue and AzureWebJobServiceBus connection string in a startup or OnInit of app without as method's parameter above. I mean, I want to a method run first of all like Program.cs in WebJob to binding or start up global variables. Can I do that in Azure Function and how to do it?
Many thanks
The attributes here are compiled into a function.jsonfile before deployment that has the info on what the binding talks to. Often things like the connection string reference app settings. Neither of these can be modified within the code itself (so a Program.cs couldn’t modify the function.json binding).
Can you share any more on your scenario? If you have multiple queues you want to listen to could you deploy a function per queue? Given the serverless nature of Functions there isn’t a downside to having extra functions deployed. Let me know - happy to see if we can help with what you need.
Edit
The suggestion below doesn't work for a Trigger, only for a Binding.
We have to wait for the team to support Key Vault endpoints in Azure Functions, see this GitHub issue.
I think what you are looking for is something called Imperative Bindings.
I've discovered them myself just yesterday and had a question about them also. With these type of bindings you can just dynamically set up the bindings you want, so you can retrieve data from somewhere else (like a global variable, or some initialization code) and use it in the binding.
The thing I have used it for is retrieving some values from Azure Key Vault, but you can also retrieve data from somewhere else of course. Some sample code.
// Retrieving the secret from Azure Key Vault via a helper class
var connectionString = await secret.Get("CosmosConnectionStringSecret");
// Setting the AppSetting run-time with the secret value, because the Binder needs it
ConfigurationManager.AppSettings["CosmosConnectionString"] = connectionString;
// Creating an output binding
var output = await binder.BindAsync<IAsyncCollector<MinifiedUrl>>(new DocumentDBAttribute("TablesDB", "minified-urls")
{
CreateIfNotExists = true,
// Specify the AppSetting key which contains the actual connection string information
ConnectionStringSetting = "CosmosConnectionString",
});
// Create the MinifiedUrl object
var create = new CreateUrlHandler();
var minifiedUrl = create.Execute(data);
// Adding the newly created object to Cosmos DB
await output.AddAsync(minifiedUrl);
There are also some other attributes you can use with imperative binding, I'm sure you'll see this in the docs (first link).
Instead of using Imperative Bindings, you can also use your application settings.
As a best practice, secrets and connection strings should be managed using app settings, rather than configuration files. This limits access to these secrets and makes it safe to store function.json in a public source control repository.
App settings are also useful whenever you want to change configuration based on the environment. For example, in a test environment, you may want to monitor a different queue or blob storage container.
App settings are resolved whenever a value is enclosed in percent signs, such as %MyAppSetting%. Note that the connection property of triggers and bindings is a special case and automatically resolves values as app settings.
The following example is an Azure Queue Storage trigger that uses an app setting %input-queue-name% to define the queue to trigger on.
{
"bindings": [
{
"name": "order",
"type": "queueTrigger",
"direction": "in",
"queueName": "%input-queue-name%",
"connection": "MY_STORAGE_ACCT_APP_SETTING"
}
]
}

how to get name of node on which my code is executing in azure fabric service?

How can I get the name of the machine on which my code is running in a Azure Fabric Cluster for logging purposes?
I am running a c# code in a fabric cluster with some nodes. I would like to log some information along with the machine name. I am using FabricRuntime, but it is not helping me. What is the best way to do this ?
Thanks.
Use the NodeContext property of the ServiceContext.
So, given the context of a service (either stateful or stateless) or actorservice you can call context.NodeContext.NodeName to retrieve the node name.
The ServiceContext has a lot of oher properties as well that can be useful for logging purposes.
For a complete example of getting node and service details see this repo.
FabricRuntime.GetNodeContext().NodeName
Well I was facing the same kind of situation and I found out that using the fabric client was very helpful. Since I am learning to use it now; the answer may lack some extensive details.
This is a sample code you can further find out the details on this link and use it according to the requirements
var fabricClient = new FabricClient();
var apps = fabricClient.QueryManager.GetApplicationListAsync().Result;
foreach (var app in apps)
{
System.Diagnostics.Debug.WriteLine($"Discovered application:'{app.ApplicationName}");
var services = fabricClient.QueryManager.GetServiceListAsync(app.ApplicationName).Result;
foreach (var service in services)
{
System.Diagnostics.Debug.WriteLine($"Discovered Service:'{service.ServiceName}");
var partitions = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).Result;
if (service.ServiceKind != System.Fabric.Query.ServiceKind.Stateful )
{
continue;
}
}
It is very helpful in querying the service fabric for required information. Now for the case of nodes you can simply do a query through the query manager like this and further use the node information to query deeper.
var nodes = fabricClient.QueryManager.GetNodeListAsync().Result;
I hope it helps someone else like me still on the same question.

Categories

Resources