Showing posts with label Azure. Show all posts
Showing posts with label Azure. Show all posts

Monday, 9 April 2018

Azure–iterate resources in all tenants for GDPR

GDPR means that we now have a policy for all data to be in UK or Europe.

So – to find where all our azure resources are

1. Install the azure PowerShell toolkik (https://docs.microsoft.com/en-gb/azure/azure-resource-manager/powershell-azure-resource-manager)

2. Run the script below to check the location of your resources are in the list of allowed locations.

# login to azure this should request secure credentials
Login-AzureRmAccount
# get a list of tenants / subscriptions
$allowedlocations = 'northeurope', 'westeurope' , 'francecentral' , 'francesouth', 'ukwest' , 'uksouth', 'germanycentral' , 'germanynortheast'
$subscriptions = Get-AzureRmSubscription
foreach($sub in $subscriptions) {
     Select-AzureRmSubscription -Subscription $sub.Id
     $resources = Get-AzureRmResource
     $resources.where({ $_.Location  -notin $allowedlocations }) 
}

Tuesday, 13 December 2016

Moveing classic resources (within subscription)

Well – according to the documentation then you can use the portal to move classic resource items around your groups.

  • Virtual machines (classic) must be moved with the cloud service.
  • Cloud service can only be moved when the move includes all its virtual machines.”

“To move classic resources to a new resource group within the same subscription, use the standard move operations through the portal, Azure PowerShell, Azure CLI, or REST API. You use the same operations as you use for moving Resource Manager resources.”

It even has a nice little picture showing it being done

I had a group with two resources – a VM and its cloud service – but the portal would not allow them to be moved.

So this nice little script does it

# prompt for credentials etc.
Login-AzureRmAccount
# select the correct subscription
Get-AzureRmSubscription -SubscriptionName "Stiona Software General" | Select-AzureRmSubscription
# get the ResourceID property of the two resources - luckily they have the same name in my case
$resources = Get-AzureRmResource -ResourceName fusionreports -ResourceGroupName fusionreports | Select -ExpandProperty ResourceId
# issue a move to the new group
Move-AzureRmResource -DestinationResourceGroupName fusionazure -ResourceId $resources

The $resources this -

/subscriptions/b9fee249-e903-4c4a-ade7-42982be9a20f/resourceGroups/fusionreports/providers/Microsoft.ClassicCompute/domainNa
mes/fusionreports
/subscriptions/b9fee249-e903-4c4a-ade7-42982be9a20f/resourceGroups/fusionreports/providers/Microsoft.ClassicCompute/virtualM
achines/fusionreports

After promt to move the old resource group was empty and the new one contained the vm and cloud service.

Nice hint from stack overflow on the use of  ExpandProperty parameter of Select-Object for getting an array of values from an array of objects.

Man – working with Azure classic sure is tough.

Monday, 10 October 2016

Powershell Azure - when you have multiple "directories"/ tenants.

Documentation didn't really cover this too well but when I tried to use powerhell to move items between subscriptions I kept getting an invalid subscription id.  I eventually deduced it was because I have two directories/tenants and was in the wrong one.

List subscriptions using

Get-AzureRmSubscription

then select one in the right tenant making sure you specify the TenantID too.

Select-AzureRmSubscription -SubscriptionId xxxxx -TenantId yyyyy
Basically it seems if you've multiple "Directories" / tenants you have to specify the tenant id.

Once you've done that, moving subscriptions etc. works for that Tenant.

Friday, 4 March 2016

DocumentDBServices now in codeplex.

So - I took the plunge and published the initial code that I wrote about here - Scalable Querying multiple Azure DocumentDB databases and collections on codeplex here https://documentdbservices.codeplex.com/.

Next steps are to create a simple web interface over the service.

Thursday, 3 March 2016

Scalable Querying multiple Azure DocumentDB databases and collections - quick blog

Azure DocumentDB is highly scalable - it seems that every 10GB or so you need a new "Collection".  My guess is each Collection gets you a new VM so you get scale!
So - if you want to run a query you need to do a request to all your collections (http) and then put all the answers together.
So - this service will do it for you
http://documentdbservices.azurewebsites.net/api/Document/?endpointUrl={YOUR ENDPOINT}&authorizationKey={YOUR KEY}&query={YOUR QUERY}

You must url encode the parameters.  I used this service - http://www.url-encode-decode.com/.
Actually - I only had to encode the authorizationKey - it contains a fair amount of special characters - everything else the browser was able to take care of.

I'll be publishing a proper web interface and maybe even putting the code in GIT over the next couple of weeks but for those who can't wait for the excitement - here's a brief how it works.

The crux of it

The class below does all the work.  
Couple of attributes store the url and key for connection and I provide instance and static methods (the instance methods using the connection details).  This should allow a user of the class to cache instances/connections to reduce overhead.

The real parallelism happens around 

 foreach (Database item in databases)
            {
                IEnumerable<DocumentCollection> dcollections = client.CreateDocumentCollectionFeedReader(item.CollectionsLink);
                foreach (DocumentCollection dc in dcollections)
                {
                    QueryDocumentCollection(query, client, retStack, tasks, item, dc);
                }
            }
            Task.WaitAll(tasks.ToArray()); 
Which calls query document collection for each collection in all the databases and waits for all of the queries to complete.
The QueryDocumentCollection calls the ExecuteQuery which creates the http request and then creates a "continuation" task to process the result.
The continuation task is added to the tasks that the above method is waiting on - the  Task.WaitAll(tasks.ToArray()) .

            Task<IQueryable<dynamic>> task = new Task<IQueryable<dynamic>>(() => ExecuteQuery(client,
                item,
                dc,
                query
                ));
            Task continuation = task.ContinueWith((prevTask) => AddCollection(retStack, prevTask));
            tasks.Add(continuation);
            task.Start();
So - each http request - is fired off async allowing the query to run in parallel across all the collections.
The ConcurrentStack<Document> is used to put all the results back together in a thread safe way.



===============the full class =====================
  /// <summary>
    /// This class provides utilities to run queries accross multiple database
    /// and subscriptions.
    /// </summary>
    public class DistributedQueryUtils
    {
        public Uri EndpointUrl { get; set; }

        public String AuthorizationKey { get; set; }
        private DocumentClient GetDocumentClient()
        {
            var client = new DocumentClient(EndpointUrl, AuthorizationKey);
            return client;
        }

        static Dictionary<String, Microsoft.Azure.Documents.DocumentCollection> collections = new Dictionary<string, DocumentCollection>();

        public async Task<DocumentCollection> GetDocumentCollectionAsync(DocumentClient client, Database database, String collection)
        {
            DocumentCollection documentCollection = null;
            // get the week number
            // check to see if we've got it
            lock (collections)
            {
                if (collections.ContainsKey(collection))
                {
                    documentCollection = collections[collection];
                }
            }
            if (null == documentCollection)
            {
                documentCollection = client.CreateDocumentCollectionQuery("dbs/" + database.Id).Where(c => c.Id == collection).AsEnumerable().FirstOrDefault();
                // If the document collection does not exist, create a new collection
                if (documentCollection == null)
                {
                    documentCollection = await client.CreateDocumentCollectionAsync("dbs/" + database.Id,
                        new DocumentCollection
                        {
                            Id = collection
                        });

                }
                lock (documentCollection)
                {
                    if (collections.ContainsKey(collection))
                    {
                        collections[collection] = documentCollection;
                    }
                    else
                    {
                        collections.Add(collection, documentCollection);
                    }
                }
            }

            return documentCollection;

        }

        public IList<Document> QueryAllDatabase(String query)
        {
            IList<Document> docs = QueryAllDatabases(query, GetDocumentClient());

            return docs;
        }
        public static IList<Document>  QueryAllDatabases(String query,
            DocumentClient client)
        {
            IList<Document> docs = QueryAllDocumentCollections(null, query, client);
           
            return docs;
        }

        public IList<Document> QueryAllDocumentCollections(String databaseName,
           String query)
        {
            return QueryAllDocumentCollections(databaseName,
                query,
                GetDocumentClient());
        }

        /// <summary>
        /// Query all document collections in the database name passed in OR 
        /// null for all databases.
        /// </summary>
        /// <param name="databaseName"></param>
        /// <param name="query"></param>
        /// <param name="client"></param>
        /// <returns></returns>
        public static IList<Document> QueryAllDocumentCollections(String databaseName, 
            String query, 
            DocumentClient client)
        {

            // get the collection of documents to look at 
            IEnumerable<Database> databases;
            List<Document> ret = new List<Document>();
            // for thread safety
            ConcurrentStack<Document> retStack = new ConcurrentStack<Document>();
            // get the database matching the name or all
            if (null != databaseName)
            {
                databases = client.CreateDatabaseQuery().Where(db => db.Id == databaseName).AsEnumerable();
            }
            else
            {
                databases = client.CreateDatabaseQuery();
            }
            List<Task> tasks = new List<Task>();
            // create a query for each collection on each database
            foreach (Database item in databases)
            {

                IEnumerable<DocumentCollection> dcollections = client.CreateDocumentCollectionFeedReader(item.CollectionsLink);
                foreach (DocumentCollection dc in dcollections)
                {
                    QueryDocumentCollection(query, client, retStack, tasks, item, dc);

                }
            }
            Task.WaitAll(tasks.ToArray());
            ret.AddRange(retStack);
            return ret;
        }

        /// <summary>
        /// Query thge document collection -
        /// fill the retStack with the Documents matching the query.
        /// The operation is not complete until the list of tasks has finished
        /// - yopu need to Task.WaitAll(tasks.ToArray());
        /// </summary>
        /// <param name="query"></param>
        /// <param name="client"></param>
        /// <param name="retStack"></param>
        /// <param name="tasks"></param>
        /// <param name="item"></param>
        /// <param name="dc"></param>
        private static void QueryDocumentCollection(String query,
            DocumentClient client,
            ConcurrentStack<Document> retStack,
            List<Task> tasks,
            Database item,
            DocumentCollection dc)
        {
            Task<IQueryable<dynamic>> task = new Task<IQueryable<dynamic>>(() => ExecuteQuery(client,
                item,
                dc,
                query
                ));
            Task continuation = task.ContinueWith((prevTask) => AddCollection(retStack, prevTask));
            tasks.Add(continuation);
            task.Start();
        }
        static IQueryable<dynamic> ExecuteQuery(DocumentClient client,
            Database db,
            DocumentCollection dc,
            String query)
        {
            return client.CreateDocumentQuery("dbs/" + db.Id + "/colls/" + dc.Id
                   , query);
        }

        static void AddCollection(ConcurrentStack<Document> retDocs,
            Task<IQueryable<dynamic>> docsToAdd)
        {
            if (!docsToAdd.IsFaulted)
            {
                foreach (Document item in docsToAdd.Result.AsEnumerable())
                {
                    retDocs.Push(item);

                }

            }
            else
            {
                throw docsToAdd.Exception;
            }
        }
    }

Web API code

     public HttpResponseMessage Get(String endpointUrl,
            String authorizationKey,
            String query)
        {
                DistributedQueryUtils dbQuery = new DistributedQueryUtils()
            {
                AuthorizationKey = authorizationKey,
                EndpointUrl = new Uri(endpointUrl)
            };
         
            IList<Document> res = dbQuery.QueryAllDatabase(query);
            StringBuilder builder = new StringBuilder();
         
                    foreach (Document d in res)
                    {
                        /*
                        d.SaveTo(ms,
                            SerializationFormattingPolicy.Indented);
                        */
                        builder.Append(d);
                    }

            var response = this.Request.CreateResponse(HttpStatusCode.OK);
            response.Content = new StringContent(builder.ToString(), Encoding.UTF8, "application/json");
     
            return response;
       
        }
Nothing too rocket science here - idealy I would have liked to write the Documents directly to the http response stream rather than making a big string but I gave up after a while.
Also - I will probably cache the DistributedQueryUtils instances to reduce http requests and add in overrides to search just a specific datbase or container.

Monday, 22 February 2016

Installing azure scripltets

I tried the instructions at https://azure.microsoft.com/en-us/documentation/articles/powershell-install-configure/ using Installing Azure PowerShell from the Gallery.
The second command Install-AzureRM failed.
“The 'Install-AzureRM' command was found in the module 'AzureRM', but the module could not be loaded.!
So I ran
Import-Module -Name AzureRM
and then Install-AzureRM and it worked.
(Actually I had to change my policy to allow scripts to run first - Set-ExecutionPolicy RemoteSigned).

Stuart:1 – MS PowerShell: 0

Monday, 19 October 2015

Report Viewer in Azure

Kept getting an issue that when deployed to azure could not find Microsoft.ReportViewer.Common v11.0.0.0 but when I tried adding to project then this files was not listed in the extensions.  Eventually I added the dll directly from the GAC (as a file) with copy local and bingo.

Do the same for Microsoft.ReportViewer.ProcessingObjectModel.

FYI – you can see these in C:\Windows\assembly but when you come to add in visual studio you need to browse the sub-directory given in the properties – MSIL.