Esempio n. 1
0
 private Task WriteFunctionsAsync(
     string outputFolder,
     IEnumerable <FunctionSchema> functions,
     CancellationToken cancellationToken)
 {
     return(WriteSchemaToFileAsync(
                Path.Combine(outputFolder, "Functions"),
                functions.ToArray(),
                f => f.Name,
                f => f.Folder,
                f => CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(f, false),
                cancellationToken));
 }
Esempio n. 2
0
        public void CreateOrAlterFunction(string functionName, IDictionary <string, string> parameters, string body, string databaseName)
        {
            try
            {
                if (parameters == null)
                {
                    parameters = new Dictionary <string, string>();
                }

                var command = CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(functionName, null, null, parameters, body);

                this.client.ExecuteControlCommand(databaseName, command);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Write the function to the file system.
        /// </summary>
        /// <param name="functionSchema">The function to write</param>
        /// <param name="rootFolder">The root folder for all the CSL files</param>
        /// <returns></returns>
        public static void WriteToFile(this FunctionSchema functionSchema, string rootFolder)
        {
            string filename = functionSchema.Name + ".csl";

            // First remove any other files with this name. In the case where you moved an object to a new folder, this will handle cleaning up the old file
            string[] existingFiles = Directory.GetFiles(rootFolder, filename, SearchOption.AllDirectories);
            if (existingFiles.Length > 0)
            {
                foreach (string file in existingFiles)
                {
                    try
                    {
                        File.Delete(file);
                    }
                    catch
                    {
                        // It's not the end of the world if this call fails
                    }
                }
            }

            // Now add write the new file to the correct location.
            string funcFolder = Path.Combine(rootFolder, "Functions");

            if (!string.IsNullOrEmpty(functionSchema.Folder))
            {
                string cleanedFolder = string.Join("", functionSchema.Folder.Split(Path.GetInvalidPathChars()));
                funcFolder = Path.Combine(funcFolder, cleanedFolder);
            }

            string destinationFile = Path.Combine(funcFolder, filename);

            if (!Directory.Exists(funcFolder))
            {
                Directory.CreateDirectory(funcFolder);
            }

            File.WriteAllText(destinationFile, CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(functionSchema, true));
        }
Esempio n. 4
0
        /// <summary>
        /// Test out the settings before saving them.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOk_Click(object sender, EventArgs e)
        {
            Cursor lastCursor = Cursor.Current;

            Cursor.Current = Cursors.WaitCursor;

            SettingsWrapper.TableFieldsOnNewLine   = cbTableFieldsOnNewLine.Checked;
            SettingsWrapper.CreateMergeEnabled     = cbCreateMerge.Checked;
            SettingsWrapper.KustoObjectDropWarning = chkTableDropWarning.Checked;
            SettingsWrapper.AADAuthority           = txtAuthority.Text;

            // Only check the Kusto settings if they changed
            if (SettingsWrapper.KustoClusterForTempDatabases != txtKustoCluster.Text || SettingsWrapper.TemporaryKustoDatabase != txtKustoDatabase.Text)
            {
                // Allow for multiple ways of specifying a cluster name
                if (string.IsNullOrEmpty(txtKustoCluster.Text))
                {
                    MessageBox.Show($"No Kusto cluster was specified.", "Missing Info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                string clusterName = QueryEngine.NormalizeClusterName(txtKustoCluster.Text);

                string databaseName = txtKustoDatabase.Text;
                if (string.IsNullOrEmpty(databaseName))
                {
                    MessageBox.Show($"No Kusto database was specified.", "Missing Info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                // If the required info is present, update the cluster textbox with the modified cluster url
                txtKustoCluster.Text = clusterName;

                // Verify connection and permissions by creating and removing a function
                var connString = new KustoConnectionStringBuilder(clusterName)
                {
                    FederatedSecurity = true,
                    InitialCatalog    = databaseName,
                    Authority         = txtAuthority.Text
                };
                var adminClient = KustoClientFactory.CreateCslAdminProvider(connString);

                try
                {
                    string functionName = "SyncKustoPermissionsTest" + Guid.NewGuid();
                    adminClient.ExecuteControlCommand(
                        CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(
                            functionName,
                            "",
                            "",
                            new Dictionary <string, string>(),
                            "{print now()}"));
                    adminClient.ExecuteControlCommand(CslCommandGenerator.GenerateFunctionDropCommand(functionName));
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("403-Forbidden"))
                    {
                        MessageBox.Show($"The current user does not have permission to create a function on cluster('{clusterName}').database('{databaseName}')", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    else if (ex.Message.Contains("failed to resolve the service name"))
                    {
                        MessageBox.Show($"Cluster {clusterName} could not be found.", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    else if (ex.Message.Contains("Kusto client failed to perform authentication"))
                    {
                        MessageBox.Show($"Could not authenticate with AAD. Please verify that the AAD Authority is specified correctly.", "Error Authenticating", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    else
                    {
                        MessageBox.Show($"Unknown error: {ex.Message}", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    return;
                }

                // Verify that the scratch database is empty
                try
                {
                    long functionCount = 0;
                    long tableCount    = 0;

                    using (var functionReader = adminClient.ExecuteControlCommand(".show functions | count"))
                    {
                        functionReader.Read();
                        functionCount = functionReader.GetInt64(0);
                    }

                    using (var tableReader = adminClient.ExecuteControlCommand(".show tables | count"))
                    {
                        tableReader.Read();
                        tableCount = tableReader.GetInt64(0);
                    }

                    if (functionCount != 0 || tableCount != 0)
                    {
                        MessageBox.Show($"Drop all functions and tables in the {txtKustoDatabase.Text} database before specifying this as the temporary database. " +
                                        $"This check is performed to reinforce the point that this databse will be wiped every time a comparison is run.",
                                        "Error Validating Empty Database",
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                        return;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Unknown error: {ex.Message}", "Error Validating Empty Database", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                // Store the settings now that we know they work
                SettingsWrapper.KustoClusterForTempDatabases = clusterName;
                SettingsWrapper.TemporaryKustoDatabase       = databaseName;
            }

            this.Close();

            Cursor.Current = lastCursor;
        }
Esempio n. 5
0
        /// <summary>
        /// Create a comparison for the node that was clicked on
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvComparison_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            string objectName = e.Node.Text;
            string sourceText = "";
            string targetText = "";

            if (_sourceSchema.Functions.ContainsKey(objectName) && e.Node.FullPath.StartsWith(_functionTreeNodeText))
            {
                sourceText = CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(_sourceSchema.Functions[objectName], true);
            }

            if (_sourceSchema.Tables.ContainsKey(objectName) && e.Node.FullPath.StartsWith(_tablesTreeNodeText))
            {
                sourceText = CslCommandGenerator.GenerateTableCreateCommand(_sourceSchema.Tables[objectName], true);
            }

            if (_targetSchema.Functions.ContainsKey(objectName) && e.Node.FullPath.StartsWith(_functionTreeNodeText))
            {
                targetText = CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(_targetSchema.Functions[objectName], true);
            }

            if (_targetSchema.Tables.ContainsKey(objectName) && e.Node.FullPath.StartsWith(_tablesTreeNodeText))
            {
                targetText = CslCommandGenerator.GenerateTableCreateCommand(_targetSchema.Tables[objectName], true);
            }

            var diffBuilder = new InlineDiffBuilder(new Differ());

            DiffPlex.DiffBuilder.Model.DiffPaneModel diff = diffBuilder.BuildDiffModel(targetText, sourceText);
            rtbSourceText.Clear();

            int longestLine = 98;

            if (diff.Lines.Any())
            {
                longestLine = Math.Max(diff.Lines.Max(l => l.Text.Length), longestLine);
            }

            foreach (DiffPlex.DiffBuilder.Model.DiffPiece line in diff.Lines)
            {
                switch (line.Type)
                {
                case DiffPlex.DiffBuilder.Model.ChangeType.Inserted:
                    rtbSourceText.SelectionBackColor = System.Drawing.Color.Yellow;
                    rtbSourceText.SelectedText       = line.Text.PadRight(longestLine);
                    break;

                case DiffPlex.DiffBuilder.Model.ChangeType.Deleted:
                    rtbSourceText.SelectionBackColor = System.Drawing.Color.Red;
                    rtbSourceText.SelectedText       = line.Text.PadRight(longestLine);
                    break;

                case DiffPlex.DiffBuilder.Model.ChangeType.Imaginary:
                    break;

                default:
                    rtbSourceText.SelectionBackColor = System.Drawing.Color.White;
                    rtbSourceText.SelectedText       = line.Text.PadRight(longestLine);
                    break;
                }

                rtbSourceText.SelectedText += "\n";
            }
        }
        /// <summary>
        /// Test out the settings before saving them.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOk_Click(object sender, EventArgs e)
        {
            Cursor lastCursor = Cursor.Current;

            Cursor.Current = Cursors.WaitCursor;

            // Allow for multiple ways of specifying a cluster name
            string clusterName = txtKustoCluster.Text;

            if (string.IsNullOrEmpty(clusterName))
            {
                MessageBox.Show($"No Kusto cluster was specified.", "Missing Info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            else if (!clusterName.EndsWith(".kusto.windows.net"))
            {
                clusterName = $"https://{clusterName}.kusto.windows.net";
            }

            string databaseName = txtKustoDatabase.Text;

            if (string.IsNullOrEmpty(databaseName))
            {
                MessageBox.Show($"No Kusto database was specified.", "Missing Info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // If the required info is present, update the cluster textbox with the modified cluster url
            txtKustoCluster.Text = clusterName;

            // Verify connection and permissions by creating and removing a function
            try
            {
                var connString = new KustoConnectionStringBuilder(clusterName)
                {
                    FederatedSecurity = true,
                    InitialCatalog    = databaseName,
                    Authority         = txtAuthority.Text
                };
                var    adminClient  = KustoClientFactory.CreateCslAdminProvider(connString);
                string functionName = "SyncKustoPermissionsTest";
                adminClient.ExecuteControlCommand(
                    CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(
                        functionName,
                        "",
                        "",
                        new Dictionary <string, string>(),
                        "{print now()}"));
                adminClient.ExecuteControlCommand(CslCommandGenerator.GenerateFunctionDropCommand(functionName));

                // Store the settings now that we know they work
                SettingsWrapper.KustoClusterForTempDatabases = clusterName;
                SettingsWrapper.TemporaryKustoDatabase       = databaseName;
                SettingsWrapper.AADAuthority = txtAuthority.Text;

                this.Close();
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("403-Forbidden"))
                {
                    MessageBox.Show($"The current user does not have permission to create a function on cluster('{clusterName}').database('{databaseName}')", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (ex.Message.Contains("failed to resolve the service name"))
                {
                    MessageBox.Show($"Cluster {clusterName} could not be found.", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (ex.Message.Contains("Kusto client failed to perform authentication"))
                {
                    MessageBox.Show($"Could not authenticate with AAD. Please verify that the AAD Authority is specified correctly.", "Error Authenticating", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    MessageBox.Show($"Unknown error: {ex.Message}", "Error Validating Permissions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            Cursor.Current = lastCursor;
        }
Esempio n. 7
0
 /// <summary>
 /// Write a function to Kusto
 /// </summary>
 /// <param name="functionSchema">The function to write</param>
 /// <param name="kustoQueryEngine">An initialized query engine for issuing the Kusto command</param>
 public static void WriteToKusto(this FunctionSchema functionSchema, QueryEngine kustoQueryEngine)
 {
     kustoQueryEngine.CreateOrAlterFunctionAsync(CslCommandGenerator.GenerateCreateOrAlterFunctionCommand(functionSchema, true), functionSchema.Name).Wait();
 }