private APSIMJob BuildAPSIMJobAndStageFiles(
            Guid jobId,
            string apsimAppPkgVersion,
            string displayName,
            string modelZipFile,
            CancellationToken ct)
        {
            var job = new APSIMJob
            {
                DisplayName                    = displayName,
                StorageCredentials             = _storageCredentials,
                BatchCredentials               = _batchCredentials,
                PoolSettings                   = _poolSettings,
                ApsimApplicationPackageVersion = apsimAppPkgVersion,
            };

            ct.ThrowIfCancellationRequested();

            job.ModelZipFileSas = _fileUploader.UploadFile(
                modelZipFile,
                jobId.ToString(),
                Path.GetFileName(modelZipFile), ct);

            ct.ThrowIfCancellationRequested();

            return(job);
        }
Exemple #2
0
        /// <summary>
        /// Returns the APSIM ZIP file and helpers like AzCopy and 7zip.
        /// </summary>
        private static IEnumerable <ResourceFile> GetResourceFiles(APSIMJob job, CloudBlobClient blobClient)
        {
            yield return(new ResourceFile(job.ModelZipFileSas, BatchConstants.MODEL_ZIPFILE_NAME));

            var toolsRef = blobClient.GetContainerReference("tools");

            foreach (CloudBlockBlob listBlobItem in toolsRef.ListBlobs())
            {
                var sas = listBlobItem.GetSharedAccessSignature(new SharedAccessBlobPolicy
                {
                    SharedAccessStartTime  = DateTime.UtcNow.AddHours(-1),
                    SharedAccessExpiryTime = DateTime.UtcNow.AddMonths(2),
                    Permissions            = SharedAccessBlobPermissions.Read,
                });
                yield return(new ResourceFile(listBlobItem.Uri.AbsoluteUri + sas, listBlobItem.Name));
            }

            var apsimRef = blobClient.GetContainerReference("apsim");

            foreach (CloudBlockBlob listBlobItem in apsimRef.ListBlobs())
            {
                if (listBlobItem.Name.ToLower().Contains(job.ApsimApplicationPackageVersion.ToLower()))
                {
                    var sas = listBlobItem.GetSharedAccessSignature(new SharedAccessBlobPolicy
                    {
                        SharedAccessStartTime  = DateTime.UtcNow.AddHours(-1),
                        SharedAccessExpiryTime = DateTime.UtcNow.AddMonths(2),
                        Permissions            = SharedAccessBlobPermissions.Read,
                    });
                    yield return(new ResourceFile(listBlobItem.Uri.AbsoluteUri + sas, listBlobItem.Name));
                }
            }
        }
Exemple #3
0
 public static JobPreparationTask ToJobPreparationTask(this APSIMJob job, Guid jobId, CloudBlobClient blobClient)
 {
     return(new JobPreparationTask
     {
         CommandLine = "cmd.exe /c jobprep.cmd",
         ResourceFiles = GetResourceFiles(job, blobClient).ToList(),
         WaitForSuccess = true,
     });
 }
Exemple #4
0
 public static JobReleaseTask ToJobReleaseTask(this APSIMJob job, Guid jobId)
 {
     return(new JobReleaseTask
     {
         //CommandLine = "cmd.exe /c rmdir /s /q " + BatchConstants.GetJobInputPath(jobId),
         //CommandLine = "cmd.exe /c echo test > " + BatchConstants.GetJobInputPath(jobId) + "\\test.txt",
         //CommandLine = "cmd.exe /c jobrelease.cmd " + BatchConstants.GetJobInputPath(jobId),
         //CommandLine = "cmd.exe /c jobrelease.cmd",
         CommandLine = "cmd.exe /c jobrelease.cmd " + job.StorageCredentials.Key,
         //CommandLine = "cmd.exe /c md c:\temp && echo test > c:\temp\test.stdout",
     });
 }
Exemple #5
0
        private static IEnumerable <ResourceFile> GetResourceFiles(APSIMJob job, CloudBlobClient blobClient)
        {
            var toolsRef = blobClient.GetContainerReference("jobmanager");

            foreach (CloudBlockBlob listBlobItem in toolsRef.ListBlobs())
            {
                var sas = listBlobItem.GetSharedAccessSignature(new SharedAccessBlobPolicy
                {
                    SharedAccessStartTime  = DateTime.UtcNow.AddHours(-1),
                    SharedAccessExpiryTime = DateTime.UtcNow.AddMonths(2),
                    Permissions            = SharedAccessBlobPermissions.Read,
                });
                yield return(new ResourceFile(listBlobItem.Uri.AbsoluteUri + sas, listBlobItem.Name));
            }
        }
        public void SubmitJob(Guid jobId, APSIMJob job, bool shouldSubmitTasks, bool autoScale)
        {
            try
            {
                var cloudJob = _batchClient.JobOperations.CreateJob(jobId.ToString(), GetPoolInfo(job.PoolSettings));
                cloudJob.DisplayName        = job.DisplayName;
                cloudJob.JobPreparationTask = job.ToJobPreparationTask(jobId, _storageAccount.CreateCloudBlobClient());
                cloudJob.JobReleaseTask     = job.ToJobReleaseTask(jobId);
                cloudJob.JobManagerTask     = job.ToJobManagerTask(jobId, _storageAccount.CreateCloudBlobClient(), shouldSubmitTasks, autoScale);

                cloudJob.Commit();
            }
            catch (AggregateException e)
            {
                throw ExceptionHelper.UnwrapAggregateException(e);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
Exemple #7
0
        public static JobManagerTask ToJobManagerTask(this APSIMJob job, Guid jobId, CloudBlobClient blobClient, bool shouldSubmitTasks, bool autoScale)
        {
            var cmd = string.Format("cmd.exe /c {0} job-manager {1} {2} {3} {4} {5} {6} {7} {8} {9}",
                                    BatchConstants.GetJobManagerPath(jobId),
                                    job.BatchCredentials.Url,
                                    job.BatchCredentials.Account,
                                    job.BatchCredentials.Key,
                                    job.StorageCredentials.Account,
                                    job.StorageCredentials.Key,
                                    jobId,
                                    BatchConstants.GetModelPath(jobId),
                                    shouldSubmitTasks,
                                    autoScale);

            return(new JobManagerTask
            {
                CommandLine = cmd,
                DisplayName = "Job manager task",
                KillJobOnCompletion = true,
                Id = BatchConstants.JOB_MANAGER_NAME,
                RunExclusive = false,
                ResourceFiles = GetResourceFiles(job, blobClient).ToList(),
            });
        }
Exemple #8
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);
            }
        }
        /// <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);
        }