Esempio n. 1
0
        /// <summary>
        /// Initialises the uploader and batch client. Asks user for an Azure licence file and saves the credentials
        /// if the credentials have not previously been set.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetCredentials(object sender, EventArgs e)
        {
            if (AzureCredentialsSetup.CredentialsExist())
            {
                // store credentials
                storageAuth = StorageCredentials.FromConfiguration();
                batchAuth   = BatchCredentials.FromConfiguration();
                poolOptions = PoolSettings.FromConfiguration();

                storageAccount = new CloudStorageAccount(new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(storageAuth.Account, storageAuth.Key), true);
                uploader       = new FileUploader(storageAccount);
                var sharedCredentials = new Microsoft.Azure.Batch.Auth.BatchSharedKeyCredentials(batchAuth.Url, batchAuth.Account, batchAuth.Key);
                try
                {
                    batchCli = BatchClient.Open(sharedCredentials);
                }
                catch (UriFormatException)
                {
                    ShowErrorMessage("Error opening Azure Batch client: credentials are invalid.");
                    AzureCredentialsSetup cred = new AzureCredentialsSetup();
                    cred.Finished += GetCredentials;
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
            }
            else
            {
                // ask user for a credentials file
                AzureCredentialsSetup cred = new AzureCredentialsSetup();
                cred.Finished += GetCredentials;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Handles the bulk of the work for submitting the job to the cloud.
        /// Zips up ApsimX (if necessary), uploads tools and ApsimX,
        /// </summary>
        /// <param name="e">Event arg, containing the job parameters</param>
        private void SubmitJob_DoWork(object o, DoWorkEventArgs e)
        {
            JobParameters jp = (JobParameters)e.Argument;

            jp.JobId                       = Guid.NewGuid();
            jp.CoresPerProcess             = 1;
            jp.JobManagerShouldSubmitTasks = true;
            jp.AutoScale                   = true;
            jp.PoolMaxTasksPerVM           = 16;
            string tmpZip = "";

            SetAzureMetaData("job-" + jp.JobId, "Owner", Environment.UserName.ToLower());

            // if jp.ApplicationPackagePath is a directory it will need to be zipped up
            if (Directory.Exists(jp.ApplicationPackagePath))
            {
                view.Status = "Zipping APSIM";

                tmpZip = Path.Combine(Path.GetTempPath(), "Apsim-tmp-X-" + Environment.UserName.ToLower() + ".zip");
                if (File.Exists(tmpZip))
                {
                    File.Delete(tmpZip);
                }

                if (CreateApsimXZip(jp.ApplicationPackagePath, tmpZip) > 0)
                {
                    view.Status = "Cancelled";
                    return;
                }

                jp.ApplicationPackagePath    = tmpZip;
                jp.ApplicationPackageVersion = Path.GetFileName(tmpZip).Substring(Path.GetFileName(tmpZip).IndexOf('-') + 1);
            }

            // add current job to the list of jobs

            // TODO : do we actually need/use the APSIMJob class?
            APSIMJob job = new APSIMJob(jp.JobDisplayName, "", jp.ApplicationPackagePath, jp.ApplicationPackageVersion, jp.Recipient, batchAuth, storageAuth, PoolSettings.FromConfiguration());

            job.PoolInfo.MaxTasksPerVM = jp.PoolMaxTasksPerVM;
            job.PoolInfo.VMCount       = jp.PoolVMCount;


            // upload tools such as 7zip, AzCopy, CMail, etc.

            view.Status = "Checking tools";

            string executableDirectory = GetExecutableDirectory();
            string toolsDir            = Path.Combine(executableDirectory, "tools");

            if (!Directory.Exists(toolsDir))
            {
                ShowErrorMessage("Tools Directory not found: " + toolsDir);
            }

            foreach (string filePath in Directory.EnumerateFiles(toolsDir))
            {
                UploadFileIfNeeded("tools", filePath);
            }

            if (jp.Recipient.Length > 0)
            {
                try
                {
                    // Store a config file into the job directory that has the e-mail config

                    string tmpConfig = Path.Combine(Path.GetTempPath(), settingsFileName);
                    using (StreamWriter file = new StreamWriter(tmpConfig))
                    {
                        file.WriteLine("EmailRecipient=" + jp.Recipient);
                        file.WriteLine("EmailSender=" + AzureSettings.Default["EmailSender"]);
                        file.WriteLine("EmailPW=" + AzureSettings.Default["EmailPW"]);
                    }

                    UploadFileIfNeeded("job-" + jp.JobId, tmpConfig);
                    File.Delete(tmpConfig);
                }
                catch (Exception err)
                {
                    ShowError(new Exception("Error writing to settings file; you may not receive an email upon job completion: ", err));
                }
            }

            // upload job manager
            UploadFileIfNeeded("jobmanager", Path.Combine(executableDirectory, "azure-apsim.exe"));



            // upload apsim
            view.Status = "Uploading APSIM Next Generation";

            UploadFileIfNeeded("apsim", jp.ApplicationPackagePath);


            // generate model files

            view.Status = "Generating model files";
            if (!Directory.Exists(jp.ModelPath))
            {
                Directory.CreateDirectory(jp.ModelPath);
            }

            try
            {
                // copy weather files to models directory to be zipped up
                foreach (Models.Weather child in Apsim.ChildrenRecursively(model).OfType <Models.Weather>())
                {
                    if (Path.GetDirectoryName(child.FullFileName) != Path.GetDirectoryName(presenter.ApsimXFile.FileName))
                    {
                        presenter.MainPresenter.ShowError("Weather file must be in the same directory as .apsimx file: " + child.FullFileName);
                        view.Status = "Cancelled";
                        return;
                    }
                    string sourceFile = child.FullFileName;
                    string destFile   = Path.Combine(jp.ModelPath, child.FileName);
                    if (!File.Exists(destFile))
                    {
                        File.Copy(sourceFile, destFile);
                    }
                    ;
                }
                // Generate .apsimx files, and if any errors are encountered, abort the job submission process.
                if (!presenter.GenerateApsimXFiles(model, jp.ModelPath))
                {
                    view.Status = "Cancelled";
                    return;
                }
            }
            catch (Exception err)
            {
                presenter.MainPresenter.ShowError(err);
                return;
            }

            tmpZip = "";

            // zip up models directory
            if (Directory.Exists(jp.ModelPath)) // this test may be unnecessary
            {
                tmpZip = GetTempFileName("Model-", ".zip", true);
                ZipFile.CreateFromDirectory(jp.ModelPath, tmpZip, CompressionLevel.Fastest, false);
                jp.ModelPath = tmpZip;
            }

            // upload models

            view.Status         = "Uploading models";
            job.ModelZipFileSas = uploader.UploadFile(jp.ModelPath, jp.JobId.ToString(), Path.GetFileName(jp.ModelPath));

            // clean up temporary model files
            if (File.Exists(tmpZip))
            {
                File.Delete(tmpZip);
            }
            if (!jp.SaveModelFiles)
            {
                if (Directory.Exists(jp.ModelPath))
                {
                    Directory.Delete(jp.ModelPath);
                }
            }

            view.Status = "Submitting Job";



            // submit job
            try
            {
                CloudJob cloudJob = batchCli.JobOperations.CreateJob(jp.JobId.ToString(), GetPoolInfo(job.PoolInfo));
                cloudJob.DisplayName        = job.DisplayName;
                cloudJob.JobPreparationTask = job.ToJobPreparationTask(jp.JobId, Microsoft.Azure.Storage.Blob.BlobAccountExtensions.CreateCloudBlobClient(storageAccount));
                cloudJob.JobReleaseTask     = job.ToJobReleaseTask(jp.JobId, Microsoft.Azure.Storage.Blob.BlobAccountExtensions.CreateCloudBlobClient(storageAccount));
                cloudJob.JobManagerTask     = job.ToJobManagerTask(jp.JobId, Microsoft.Azure.Storage.Blob.BlobAccountExtensions.CreateCloudBlobClient(storageAccount), jp.JobManagerShouldSubmitTasks, jp.AutoScale);

                cloudJob.Commit();
            }
            catch (Exception err)
            {
                ShowError(err);
            }

            view.Status = "Job Successfully submitted";

            if (jp.AutoDownload)
            {
                AzureResultsDownloader dl = new AzureResultsDownloader(jp.JobId, jp.JobDisplayName, jp.OutputDir, null, true, jp.Summarise, true, true, true);
                dl.DownloadResults(true);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Handles the bulk of the work for submitting the job to the cloud.
        /// Zips up ApsimX (if necessary), uploads tools and ApsimX,
        /// </summary>
        /// <param name="e">Event arg, containing the job parameters</param>
        private void SubmitJob_DoWork(object o, DoWorkEventArgs e)
        {
            JobParameters jp = (JobParameters)e.Argument;

            jp.JobId                       = Guid.NewGuid();
            jp.CoresPerProcess             = 1;
            jp.JobManagerShouldSubmitTasks = true;
            jp.AutoScale                   = true;
            jp.PoolMaxTasksPerVM           = 16;
            string tmpZip = "";

            SetAzureMetaData("job-" + jp.JobId, "Owner", Environment.UserName.ToLower());

            // if jp.ApplicationPackagePath is a directory it will need to be zipped up
            if (Directory.Exists(jp.ApplicationPackagePath))
            {
                view.Status = "Zipping APSIM";

                tmpZip = Path.Combine(Path.GetTempPath(), "Apsim-tmp-X-" + Environment.UserName.ToLower() + ".zip");
                if (File.Exists(tmpZip))
                {
                    File.Delete(tmpZip);
                }

                if (createApsimXZip(jp.ApplicationPackagePath, tmpZip) > 0)
                {
                    ShowError("Error zipping up Apsim");
                }

                jp.ApplicationPackagePath    = tmpZip;
                jp.ApplicationPackageVersion = Path.GetFileName(tmpZip).Substring(Path.GetFileName(tmpZip).IndexOf('-') + 1);
            }

            // add current job to the list of jobs

            // TODO : do we actually need/use the APSIMJob class?
            APSIMJob job = new APSIMJob(jp.JobDisplayName, "", jp.ApplicationPackagePath, jp.ApplicationPackageVersion, jp.Recipient, batchCredentials, storageCredentials, PoolSettings.FromConfiguration());

            job.PoolInfo.MaxTasksPerVM = jp.PoolMaxTasksPerVM;
            job.PoolInfo.VMCount       = jp.PoolVMCount;


            // upload tools such as 7zip, AzCopy, CMail, etc.

            view.Status = "Checking tools";

            string executableDirectory = GetExecutableDirectory();
            string toolsDir            = Path.Combine(executableDirectory, "tools");

            if (!Directory.Exists(toolsDir))
            {
                ShowError("Tools Directory not found: " + toolsDir);
            }

            foreach (string filePath in Directory.EnumerateFiles(toolsDir))
            {
                UploadFileIfNeeded("tools", filePath);
            }

            if (jp.Recipient.Length > 0)
            {
                try
                {
                    // Store a config file into the job directory that has the e-mail config

                    string tmpConfig = Path.Combine(Path.GetTempPath(), SETTINGS_FILENAME);
                    using (StreamWriter file = new StreamWriter(tmpConfig))
                    {
                        file.WriteLine("EmailRecipient=" + jp.Recipient);
                        file.WriteLine("EmailSender=" + AzureSettings.Default["EmailSender"]);
                        file.WriteLine("EmailPW=" + AzureSettings.Default["EmailPW"]);
                    }

                    UploadFileIfNeeded("job-" + jp.JobId, tmpConfig);
                    File.Delete(tmpConfig);
                }
                catch (Exception ex)
                {
                    ShowError("Error writing to settings file; you may not receive an email upon job completion: " + ex.ToString());
                }
            }

            // upload job manager
            UploadFileIfNeeded("jobmanager", Path.Combine(executableDirectory, "azure-apsim.exe"));



            // upload apsim
            view.Status = "Uploading APSIM Next Generation";

            UploadFileIfNeeded("apsim", jp.ApplicationPackagePath);


            // create models

            // TODO : show error message if other files already exist in model output directory?
            //        may be necessary if using  a user-selected directory

            string path = "";



            // generate model files

            view.Status = "Generating model files";
            if (!Directory.Exists(jp.ModelPath))
            {
                Directory.CreateDirectory(jp.ModelPath);
            }

            // generate xml
            string xml = "";

            foreach (Simulation sim in Runner.AllSimulations(model))
            {
                path = Path.Combine(jp.ModelPath, sim.Name + ".apsimx");
                // if weather file is not in the same directory as the .apsimx file, display an error then abort
                foreach (var child in sim.Children)
                {
                    if (child is Models.Weather)
                    {
                        string childPath = sim.Children.OfType <Models.Weather>().ToList()[0].FileName;
                        if (Path.GetDirectoryName(childPath) != "")
                        {
                            ShowError(childPath + " must be in the same directory as the .apsimx file" + (sim.FileName != null ? " (" + Path.GetDirectoryName(sim.FileName) + ")" : ""));
                            view.Status = "Cancelled";
                            return;
                        }
                        string sourcePath = sim.Children.OfType <Models.Weather>().ToList()[0].FullFileName;
                        string destPath   = Path.Combine(jp.ModelPath, sim.Children.OfType <Models.Weather>().ToList()[0].FileName);
                        if (!File.Exists(destPath))
                        {
                            File.Copy(sourcePath, destPath);
                        }
                    }
                }
                xml = Apsim.Serialise(sim);
                // delete model file if it already exists
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                string pattern = @"<\?xml[^<>]+>";
                System.Text.RegularExpressions.Regex rx = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                var matches = rx.Matches(xml);
                xml = "<Simulations xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" Version=\"23\">\r\n<Name>" + sim.Name + "</Name>\r\n" + xml.Replace(matches[0].ToString(), "") + "<DataStore><Name>DataStore</Name><AutoExport>false</AutoExport><MaximumResultsPerPage>0</MaximumResultsPerPage></DataStore><ExplorerWidth>296</ExplorerWidth></Simulations>";
                // write xml to file
                using (FileStream fs = File.Create(path))
                {
                    Byte[] info = new UTF8Encoding(true).GetBytes(xml);
                    fs.Write(info, 0, info.Length);
                }
            }

            tmpZip = "";

            // zip up models directory
            if (Directory.Exists(jp.ModelPath)) // this test may be unnecessary
            {
                tmpZip = GetTempFileName("Model-", ".zip", true);
                ZipFile.CreateFromDirectory(jp.ModelPath, tmpZip, CompressionLevel.Fastest, false);
                jp.ModelPath = tmpZip;
            }

            // upload models

            view.Status         = "Uploading models";
            job.ModelZipFileSas = uploader.UploadFile(jp.ModelPath, jp.JobId.ToString(), Path.GetFileName(jp.ModelPath));

            // clean up temporary model files
            if (File.Exists(tmpZip))
            {
                File.Delete(tmpZip);
            }
            if (!jp.SaveModelFiles)
            {
                if (Directory.Exists(jp.ModelPath))
                {
                    Directory.Delete(jp.ModelPath);
                }
            }

            view.Status = "Submitting Job";



            // submit job
            try
            {
                CloudJob cloudJob = batchClient.JobOperations.CreateJob(jp.JobId.ToString(), GetPoolInfo(job.PoolInfo));
                cloudJob.DisplayName        = job.DisplayName;
                cloudJob.JobPreparationTask = job.ToJobPreparationTask(jp.JobId, storageAccount.CreateCloudBlobClient());
                cloudJob.JobReleaseTask     = job.ToJobReleaseTask(jp.JobId, storageAccount.CreateCloudBlobClient());
                cloudJob.JobManagerTask     = job.ToJobManagerTask(jp.JobId, storageAccount.CreateCloudBlobClient(), jp.JobManagerShouldSubmitTasks, jp.AutoScale);

                cloudJob.Commit();
            } catch (Exception ex)
            {
                ShowError(ex.ToString());
            }

            view.Status = "Job Successfully submitted";

            // in theory, instantiating an AzureResultsDownloader here and passing in this job's ID and name, then calling its DownloadResults() method would allow
            // for automatic job downloading as soon as the job is finished. The trouble is it needs an AzureJobDisplayPresenter (for progress bar updating, etc).

            // explorerPresenter.MainPresenter.ShowMessage("Job Successfully submitted", Simulation.ErrorLevel.Information);
            // AzureResultsDownloader dl = new AzureResultsDownloader(jp.JobId, jp.JobDisplayName, jp.OutputDir, this.explorerPresenter, true, false, false);
        }