Example #1
0
    /// <summary>
    /// Attempt to log any detailed information we find about the failed web request
    /// </summary>
    /// <param name="webException"></param>
    /// <param name="onlineStatusLog"></param>
    private static void AttemptToLogWebException(WebException webException, string description, TaskStatusLogs onlineStatusLog)
    {
        if (onlineStatusLog == null)
        {
            return;                         //No logger? nothing to do
        }
        try
        {
            if (string.IsNullOrWhiteSpace(description))
            {
                description = "web request failed";
            }
            var response     = webException.Response;
            var responseText = GetWebResponseAsText(response);
            response.Close();
            if (responseText == null)
            {
                responseText = "";
            }

            onlineStatusLog.AddError(description + ": " + webException.Message + "\r\n" + responseText + "\r\n");
        }
        catch (Exception ex)
        {
            onlineStatusLog.AddError("Error in web request exception: " + ex.Message);
            return;
        }
    }
Example #2
0
    /// <summary>
    /// Query for each of the specified groups and pull down their members list from Azure
    /// </summary>
    /// <param name="azureSessionToken"></param>
    /// <param name="groupsToRolesSyncList"></param>
    private async Task GeneratGroupsMembersListFromAzureGroups(GraphServiceClient azureGraph, IEnumerable <ProvisionConfigExternalDirectorySync.SynchronizeGroupToGroup> groupsToGroupsSyncList)
    {
        foreach (var groupToRetrieve in groupsToGroupsSyncList)
        {
            _statusLogs.AddStatus("Azure getting group: " + groupToRetrieve.SourceGroupName);
            var thisGroupAsSet = await azureGraph.Groups.Request().Select(x => new { x.Id, x.DisplayName }).Filter("displayName eq '" + groupToRetrieve.SourceGroupName + "'").GetAsync();

            //If the group does not exist in Azure, not the error condition
            if (thisGroupAsSet.Count < 1)
            {
                _statusLogs.AddError("Azure AD group does not exist" + groupToRetrieve.SourceGroupName);
                throw new Exception("814-722: Azure AD group does not exist" + groupToRetrieve.SourceGroupName);
            }
            var thiGroupId = thisGroupAsSet.CurrentPage[0].Id;

            //https://docs.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=http
            //UNDONE: Filter down to just USERS and SUB-GROUPS

            var thisGroupsMembers = await azureGraph.Groups[thiGroupId].Members.Request().GetAsync();
            //TEST: Test paging by forcing  small page size
            //var thisGroupsMembers = await azureGraph.Groups[thiGroupId].Members.Request().Top(2).GetAsync();

            //Get all the users in the group and sub-groups
            await AzureRecurseGroupsGenerateGroupMembersList(azureGraph, thisGroupsMembers, groupToRetrieve);
        }
    }
Example #3
0
 /// <summary>
 /// Adds a keyed item to the dictionary
 /// </summary>
 /// <param name="key"></param>
 /// <param name="item"></param>
 /// <param name="statusLogger">If non-NULL; then trap and record errors,  If NULL the error will get thrown upward</param>
 public void AddItem(string key, T item, TaskStatusLogs statusLogger = null)
 {
     //There are cases where building the dictionary may fail, such as if the incoming data has
     //duplicate ID entries.  If we have a status logger, we want to log the error and then
     //continue onward
     try
     {
         _dictionary.Add(key, item);
     }
     catch (Exception exAddDictionaryItem)
     {
         //If we have an error logger, then log the error
         if (statusLogger != null)
         {
             string itemDescription = "null item";
             if (item != null)
             {
                 itemDescription = item.ToString();
             }
             statusLogger.AddError("Error building lookup dictionary. Item: " + itemDescription + ", " + exAddDictionaryItem.ToString());
         }
         else //Otherwise thrown the error upward
         {
             throw;
         }
     }
 }
Example #4
0
    /// <summary>
    /// If we have Project Mapping information, generate a project based path for the download
    /// </summary>
    /// <param name="basePath"></param>
    /// <param name="projectList"></param>
    /// <param name="projectId"></param>
    /// <returns></returns>
    public static string EnsureProjectBasedPath(string basePath, IProjectsList projectList, IHasProjectId project, TaskStatusLogs statusLog)
    {
        //If we have no project list to do lookups in then just return the base path
        if (projectList == null)
        {
            return(basePath);
        }

        //Look up the project name
        var projWithId = projectList.FindProjectWithId(project.ProjectId);

        if (projWithId == null)
        {
            statusLog.AddError("Project not found with id " + project.ProjectId);
            return(basePath);
        }

        //Turn the project name into a directory name
        var safeDirectoryName = GenerateWindowsSafeFilename(projWithId.Name);

        var pathWithProject = Path.Combine(basePath, safeDirectoryName);

        //If needed, create the directory
        if (!Directory.Exists(pathWithProject))
        {
            Directory.CreateDirectory(pathWithProject);
        }

        return(pathWithProject);
    }
Example #5
0
    /// <summary>
    /// If we have Project Mapping information, generate a project based path for the download
    /// </summary>
    /// <param name="basePath"></param>
    /// <param name="projectList"></param>
    /// <param name="projectId"></param>
    /// <returns></returns>
    public static string EnsureProjectBasedPath(string basePath, IProjectsList projectList, IHasProjectId project, TaskStatusLogs statusLog)
    {
        //If we have no project list to do lookups in then just return the base path
        if (projectList == null) return basePath;

        //Look up the project name
        var projWithId = projectList.FindProjectWithId(project.ProjectId);
        if(projWithId == null)
        {
            statusLog.AddError("Project not found with id " + project.ProjectId);
            return basePath;
        }

        //Turn the project name into a directory name
        var safeDirectoryName = GenerateWindowsSafeFilename(projWithId.Name);

        var pathWithProject = Path.Combine(basePath, safeDirectoryName);
        //If needed, create the directory
        if(!Directory.Exists(pathWithProject))
        {
            Directory.CreateDirectory(pathWithProject);
        }

        return pathWithProject;
    }
Example #6
0
        /// <summary>
        /// Provision a site based on a file based manifest
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnProvisionSiteFromManifestFile_Click(object sender, EventArgs e)
        {
            var statusLogs = new TaskStatusLogs();

            statusLogs.AddStatus("Starting...");
            UpdateStatusText(statusLogs, true);

            string pathSecrets = txtPathToSecrets.Text;

            if (!File.Exists(pathSecrets))
            {
                MessageBox.Show("Secrets file does not exist at specified path (" + pathSecrets + ")");
                return;
            }

            string pathProvisionPlan = txtPathToFileProvisioningConfig.Text;

            if (!File.Exists(pathProvisionPlan))
            {
                MessageBox.Show("Config file does not exist at specified path (" + pathProvisionPlan + ")");
                return;
            }



            string pathOutput =
                Path.Combine(
                    Path.GetDirectoryName(pathProvisionPlan),
                    "out");

            //Show the user a command line that they can use to run this same work
            GenerateProvisioningCommandLine(
                CommandLineParser.Command_ProvisionFromFileManifest,
                pathSecrets,
                pathProvisionPlan,
                pathOutput);

            //Run the work
            try
            {
                ProvisionFromFileManifest(statusLogs, pathSecrets, pathProvisionPlan, pathOutput);
            }
            catch (Exception ex)
            {
                statusLogs.AddError("Untrapped error: " + ex.Message);
            }

            //Update the status text to it's final state
            UpdateStatusText(statusLogs, true);

            //Open the file explorer to the output directory
            if (Directory.Exists(pathOutput))
            {
                System.Diagnostics.Process.Start(pathOutput);
            }
        }
Example #7
0
    /// <summary>
    /// Remaps the 'repository-location' node of the Data Source XML
    /// </summary>
    /// <param name="xnodeRepository"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapSingleWorkbooksRepositoryNode(XmlDocument xmlDoc, XmlNode xNodeDatasource, ITableauServerSiteInfo serverMapInfo, bool ignoreIfMissing, TaskStatusLogs statusLog)
    {
        var siteId = serverMapInfo.SiteId;

        //Get the XML sub mode we need
        var xnodeRepository = xNodeDatasource.SelectSingleNode("repository-location");

        if (xnodeRepository == null)
        {
            if (ignoreIfMissing)
            {
                return;
            }

            statusLog.AddError("Workbook remapper, no workbook 'repository-location' node found");
            return;
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        helper_SetRespositorySite(xmlDoc, xnodeRepository, serverMapInfo);

        ///////////////////////////////////////////////////////////////////////////////////////
        var attrPath = xnodeRepository.Attributes["path"];

        if (attrPath != null)
        {
            //Is there a site specified
            if (!string.IsNullOrWhiteSpace(siteId))
            {
                attrPath.Value = "/t/" + siteId + "/workbooks";
            }
            else //Default site
            {
                attrPath.Value = "/workbooks";
            }
        }
        else
        {
            statusLog.AddError("Workbook remapper 'path' attribute not found");
        }
    }
Example #8
0
    /// <summary>
    /// There should only be one *.twb file in the unzipped set of files
    /// </summary>
    /// <returns></returns>
    private string GetPathToUnzippedTwb()
    {
        var twbFiles = Directory.EnumerateFiles(this.UnzipDirectory, "*.twb");

        foreach (var twb in twbFiles)
        {
            return(twb);
        }

        _statusLog.AddError("Twb editor; no twb file found");
        return(null);
    }
    /// <summary>
    /// Sign us out
    /// </summary>
    /// <param name="serverUrls"></param>
    public void SignOut(TableauServerUrls serverUrls)
    {
        if (!_isSignedIn)
        {
            StatusLog.AddError("Session not signed in. Sign out aborted");
        }

        //Perform the sign out
        var signOut = new TableauServerSignOut(serverUrls, this);

        signOut.ExecuteRequest();

        _isSignedIn = false;
    }
Example #10
0
    /// <summary>
    /// Creates a TWB file that points to the CSV file
    /// </summary>
    /// <param name="pathReportCsv"></param>
    private void Execute_GenerateSiteInventoryFile_Twb(string pathReportCsv)
    {
        _statusLog.AddStatusHeader("Generate site inventory TWB");

        try
        {
            //Calculate the name/path for the output TWB.  It will match the name/path of the CSV file
            string pathTwbOut = PathHelper.GetInventoryTwbPathMatchingCsvPath(pathReportCsv);
            this.StatusLog.AddStatusHeader("Generating Tableau Workbook " + pathTwbOut);


            var twbGenerateFromTemplate = new TwbReplaceCSVReference(
                PathHelper.GetInventoryTwbTemplatePath(),   //*.twb we are using as our template
                pathTwbOut,                                 //Output *.twb we are generating
                "siteInventory",                            //Datasource name in tempalte workbook
                pathReportCsv,                              //CSV file we want to associate with the datasource above
                _statusLog);

            //Transform the template into the output file
            bool successRemapping = twbGenerateFromTemplate.Execute();
            if (!successRemapping)
            {
                this.StatusLog.AddError("Error generating site inventory TWB. No data source could be found to remap");
            }


            //Store it as our output
            if (File.Exists(pathTwbOut))
            {
                _pathGeneratedSiteInventoryReportTwb = pathTwbOut;
            }
        }
        catch (Exception ex)
        {
            StatusLog.AddError("Error generating Twb file: " + ex.ToString());
        }
    }
Example #11
0
    /// <summary>
    /// Attempt to log any detailed information we find about the failed web request
    /// </summary>
    /// <param name="webException"></param>
    /// <param name="onlineStatusLog"></param>
    private static void AttemptToLogWebException(WebException webException, string description, TaskStatusLogs onlineStatusLog)
    {
        if (onlineStatusLog == null)
        {
            return;                         //No logger? nothing to do
        }
        try
        {
            if (string.IsNullOrWhiteSpace(description))
            {
                description = "web request failed";
            }
            string responseText = "";

            //NOTE: In some cases (e.g. time-out) the response may be NULL
            var response = webException.Response;
            if (response != null)
            {
                responseText = GetWebResponseAsText(response);
                response.Close();
            }

            //Cannonicalize a blank result...
            if (string.IsNullOrEmpty(responseText))
            {
                responseText = "";
            }

            onlineStatusLog.AddError(description + ": " + webException.Message + "\r\n" + responseText + "\r\n");
        }
        catch (Exception ex)
        {
            onlineStatusLog.AddError("811-830: Error in web request exception: " + ex.Message);
            return;
        }
    }
    /// <summary>
    /// Finds and changes a datasource reference inside a Workbook. Changes the CSV file the data source points to
    /// </summary>
    /// <param name="xmlDoc"></param>
    /// <param name="datasourceName"></param>
    /// <param name="pathToTargetCsv"></param>
    /// <param name="statusLog"></param>
    private bool RemapDatasourceCsvReference(XmlDocument xmlDoc, string datasourceName, string pathToTargetCsv, TaskStatusLogs statusLog)
    {
        int    replaceItemCount           = 0;
        string newCsvDirectory            = Path.GetDirectoryName(_datasourceNewCsvPath);
        string newCsvFileName             = Path.GetFileName(_datasourceNewCsvPath);
        string newDatasourceRelationName  = Path.GetFileNameWithoutExtension(newCsvFileName) + "#csv";
        string newDatasourceRelationTable = "[" + newDatasourceRelationName + "]";
        string seekDatasourceCaption      = _datasourceName;

        var xDataSources = xmlDoc.SelectNodes("workbook/datasources/datasource");

        if (xDataSources != null)
        {
            //Look through the data sources
            foreach (XmlNode xnodeDatasource in xDataSources)
            {
                //If the data source is matching the caption we are looking for
                if (XmlHelper.SafeParseXmlAttribute(xnodeDatasource, "caption", "") == seekDatasourceCaption)
                {
                    var xnodeConnection = xnodeDatasource.SelectSingleNode("connection");
                    //It should be 'textscan', it would be unexpected if it were not
                    if (XmlHelper.SafeParseXmlAttribute(xnodeConnection, "class", "") == "textscan")
                    {
                        //Point to the new directory/path
                        xnodeConnection.Attributes["directory"].Value = newCsvDirectory;
                        xnodeConnection.Attributes["filename"].Value  = newCsvFileName;

                        //And it's got a Relation we need to update
                        var xNodeRelation = xnodeConnection.SelectSingleNode("relation");
                        xNodeRelation.Attributes["name"].Value  = newDatasourceRelationName;
                        xNodeRelation.Attributes["table"].Value = newDatasourceRelationTable;

                        replaceItemCount++;
                    }
                    else
                    {
                        _statusLog.AddError("Data source remap error. Expected data source to be 'textscan'");
                    }
                } //end if
            }     //end foreach
        }         //end if

        return(replaceItemCount > 0);
    }
Example #13
0
        /// <summary>
        /// Called to run us in commandn line mode
        /// </summary>
        /// <param name="commandLine"></param>
        internal void RunStartupCommandLine_Inner(TaskStatusLogs statusLogs)
        {
            statusLogs.AddStatusHeader("Processing command line");
            string pathProvisionPlan = AppSettings.CommandLine_PathProvisionPlan;
            string pathSecrets       = AppSettings.CommandLine_PathSecrets;
            string pathOutput        = AppSettings.CommandLine_PathOutput;

            //If an output directory was not specified, then output into an "out" subdirectory in the directory where the provision plan is
            if (string.IsNullOrWhiteSpace(pathOutput))
            {
                pathOutput = Path.Combine(
                    Path.GetDirectoryName(pathProvisionPlan),
                    "out");
            }

            //====================================================================================
            //Based on the command specified, run the specified task
            //====================================================================================
            switch (AppSettings.CommandLine_Command)
            {
            case CommandLineParser.Command_ProvisionFromAzure:
                //Update the paths in the UI so the user can see & re-run them if they want
                txtPathToSecrets.Text = pathSecrets;
                txtPathToAzureAdProvisioningConfig.Text = pathProvisionPlan;

                //Run the work...
                ProvisionFromAzureAd(statusLogs, pathSecrets, pathProvisionPlan, pathOutput);
                break;

            case CommandLineParser.Command_ProvisionFromFileManifest:
                //Update the paths in the UI so the user can see & re-run them if they want
                txtPathToSecrets.Text = pathSecrets;
                txtPathToFileProvisioningConfig.Text = pathProvisionPlan;

                //Run the work...
                ProvisionFromFileManifest(statusLogs, pathSecrets, pathProvisionPlan, pathOutput);
                break;

            default:
                statusLogs.AddError("1101-432: Unknown command: " + AppSettings.CommandLine_Command);
                break;
            }
        }
    /// <summary>
    /// Remaps global references in the workbook that refer to the site/server
    /// </summary>
    /// <param name="xmlDoc"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapWorkbookGlobalReferences(XmlDocument xmlDoc, ITableauServerSiteInfo serverMapInfo, TaskStatusLogs statusLog)
    {
        var xnodeWorkbook = xmlDoc.SelectSingleNode("//workbook");
        if(xnodeWorkbook == null)
        {
            statusLog.AddError("Workbook remapper, 'workbook' node not found");
            return;
        }

        //See if there is an an XML base node
        var attrXmlBase = xnodeWorkbook.Attributes["xml:base"];
        if(attrXmlBase != null)
        {
            attrXmlBase.Value = serverMapInfo.ServerNameWithProtocol;
        }

        //We may also have a repository node
        RemapSingleWorkbooksRepositoryNode(xmlDoc, xnodeWorkbook, serverMapInfo, true, statusLog);
    }
Example #15
0
    /// <summary>
    /// Remaps global references in the workbook that refer to the site/server
    /// </summary>
    /// <param name="xmlDoc"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapWorkbookGlobalReferences(XmlDocument xmlDoc, ITableauServerSiteInfo serverMapInfo, TaskStatusLogs statusLog)
    {
        var xnodeWorkbook = xmlDoc.SelectSingleNode("//workbook");

        if (xnodeWorkbook == null)
        {
            statusLog.AddError("Workbook remapper, 'workbook' node not found");
            return;
        }

        //See if there is an an XML base node
        var attrXmlBase = xnodeWorkbook.Attributes["xml:base"];

        if (attrXmlBase != null)
        {
            attrXmlBase.Value = serverMapInfo.ServerNameWithProtocol;
        }

        //We may also have a repository node
        RemapSingleWorkbooksRepositoryNode(xmlDoc, xnodeWorkbook, serverMapInfo, true, statusLog);
    }
Example #16
0
    /// <summary>
    /// Remaps the 'repository-location' node of the Data Source XML
    /// </summary>
    /// <param name="xnodeRepository"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapSingleWorkbooksRepositoryNode(XmlDocument xmlDoc, XmlNode xNodeDatasource, ITableauServerSiteInfo serverMapInfo, bool ignoreIfMissing, TaskStatusLogs statusLog)
    {
        var siteId = serverMapInfo.SiteId;

        //Get the XML sub mode we need
        var xnodeRepository = xNodeDatasource.SelectSingleNode("repository-location");
        if (xnodeRepository == null)
        {
            if (ignoreIfMissing) return;

            statusLog.AddError("Workbook remapper, no workbook 'repository-location' node found");
            return;
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        helper_SetRespositorySite(xmlDoc, xnodeRepository, serverMapInfo);

        ///////////////////////////////////////////////////////////////////////////////////////
        var attrPath = xnodeRepository.Attributes["path"];
        if (attrPath != null)
        {
            //Is there a site specified
            if (!string.IsNullOrWhiteSpace(siteId))
            {
                attrPath.Value = "/t/" + siteId + "/workbooks";
            }
            else //Default site
            {
                attrPath.Value = "/workbooks";
            }
        }
        else
        {
            statusLog.AddError("Workbook remapper 'path' attribute not found");
        }
    }
Example #17
0
    /// <summary>
    /// Finds and changes a datasource reference inside a Workbook. Changes the CSV file the data source points to
    /// </summary>
    /// <param name="xmlDoc"></param>
    /// <param name="oldDatasourceFilename">Filenane (without path) of the datasource we want to replace. Case insensitive</param>
    /// <param name="pathToTargetCsv"></param>
    /// <param name="statusLog"></param>
    private bool RemapDatasourceCsvReference(XmlDocument xmlDoc, string oldDatasourceFilename, string pathToTargetCsv, TaskStatusLogs statusLog)
    {
        int    replaceItemCount           = 0;
        string newCsvDirectory            = Path.GetDirectoryName(_datasourceNewCsvPath);
        string newCsvFileName             = Path.GetFileName(_datasourceNewCsvPath);
        string newDatasourceRelationName  = Path.GetFileNameWithoutExtension(newCsvFileName) + "#csv";
        string newDatasourceRelationTable = "[" + newDatasourceRelationName + "]";

        var xDataSources = xmlDoc.SelectNodes("workbook/datasources/datasource");

        if (xDataSources != null)
        {
            //Look through the data sources
            foreach (XmlNode xnodeDatasource in xDataSources)
            {
                var xConnections = xnodeDatasource.SelectNodes(".//connection");
                if (xConnections != null)
                {
                    foreach (XmlNode xThisConnection in xConnections)
                    {
                        //If its a 'textscan' (CSV) and the file name matches the expected type, then this is a datasource's connection we want to remap
                        //to point to a new CSV file
                        if ((XmlHelper.SafeParseXmlAttribute(xThisConnection, "class", "") == "textscan") &&
                            (string.Compare(XmlHelper.SafeParseXmlAttribute(xThisConnection, "filename", ""),
                                            oldDatasourceFilename, true) == 0))
                        {
                            //Find any relation nodes beneath the datasource
                            //Newer version of the document model put the textscan connection inside a federated data source
                            //to deal with that, we need to look upward from the connection and adjacent in the DOM to find the correct
                            //node to replace. This is done by looking at child nodes in the datasource
                            var     xNodeAllConnectionRelations = xnodeDatasource.SelectNodes(".//relation");
                            XmlNode xNodeRelation = null;
                            if (xNodeAllConnectionRelations != null)
                            {
                                if (xNodeAllConnectionRelations.Count == 1)
                                {
                                    xNodeRelation = xNodeAllConnectionRelations[0];
                                }
                                else
                                {
                                    statusLog.AddError("CSV replacement. Expected 1 Relation in data source definition, actual " + xNodeAllConnectionRelations.Count.ToString());
                                }
                            }


                            //Only if we have all the elements need to replace, should we go ahead with the replacement
                            if ((xNodeRelation != null) && (xThisConnection != null))
                            {
                                //Point to the new directory/path
                                xThisConnection.Attributes["directory"].Value = newCsvDirectory;
                                xThisConnection.Attributes["filename"].Value  = newCsvFileName;

                                xNodeRelation.Attributes["name"].Value  = newDatasourceRelationName;
                                xNodeRelation.Attributes["table"].Value = newDatasourceRelationTable;

                                replaceItemCount++;
                            }
                        }
                    } //end: foreach xThisConnection
                }
            }         //end foreach
        }             //end if

        return(replaceItemCount > 0);
    }
        /// <summary>
        /// Executes the authentication request against the Tableau server
        /// </summary>
        public bool ExecuteRequest()
        {
            var    webRequest = WebRequest.Create(_onlineUrls.UrlLogin);
            string bodyText   = xmlLogIn;

            bodyText = bodyText.Replace("{{iwsUserName}}", _userName);
            bodyText = bodyText.Replace("{{iwsPassword}}", _password);
            bodyText = bodyText.Replace("{{iwsSiteUrl}}", _siteUrlSegment);
            AssertTemplateFullyReplaced(bodyText);

            //===============================================================================================
            //Make the sign in request, trap and note, and rethrow any errors
            //===============================================================================================
            try
            {
                SendRequestContents(webRequest, bodyText);
            }
            catch (Exception exSendRequest)
            {
                StatusLog.AddError("Error sending sign in request: " + exSendRequest);
                throw;
            }


            //===============================================================================================
            //Get the web response, trap and note, and rethrow any errors
            //===============================================================================================
            WebResponse response;

            try
            {
                response = webRequest.GetResponse();
            }
            catch (Exception exResponse)
            {
                StatusLog.AddError("Error returned from sign in response: " + exResponse);
                throw;
            }

            var allHeaders = response.Headers;
            var cookies    = allHeaders["Set-Cookie"];

            _logInCookies = cookies; //Keep any cookies

            //===============================================================================================
            //Get the web response's XML payload, trap and note, and rethrow any errors
            //===============================================================================================
            XmlDocument xmlDoc;

            try
            {
                xmlDoc = GetWebResponseAsXml(response);
            }
            catch (Exception exSignInResponse)
            {
                StatusLog.AddError("Error returned from sign in xml response: " + exSignInResponse);
                throw;
            }

            var nsManager      = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
            var credentialNode = xmlDoc.SelectSingleNode("//iwsOnline:credentials", nsManager);
            var siteNode       = xmlDoc.SelectSingleNode("//iwsOnline:site", nsManager);

            _logInSiteId = siteNode.Attributes["id"].Value;
            _logInToken  = credentialNode.Attributes["token"].Value;

            //Adding the UserId to the log-in return was a feature that was added late in the product cycle.
            //For this reason this code is going to defensively look to see if hte attribute is there
            var    userNode = xmlDoc.SelectSingleNode("//iwsOnline:user", nsManager);
            string userId   = null;

            if (userNode != null)
            {
                var userIdAttribute = userNode.Attributes?["id"];
                if (userIdAttribute != null)
                {
                    userId = userIdAttribute.Value;
                }
                _logInUserId = userId;
            }

            //Output some status text...
            if (!string.IsNullOrWhiteSpace(userId))
            {
                StatusLog.AddStatus("Log-in returned user id: '" + userId + "'", -10);
            }
            else
            {
                StatusLog.AddStatus("No User Id returned from log-in request");
                return(false);  //Failed sign in
            }

            return(true); //Success
        }
Example #19
0
    /// <summary>
    /// Called to attempt to execute a custom command (to be run after the user logs in)
    /// </summary>
    /// <param name="onlineLogin"></param>
    /// <param name="customCommand"></param>
    private void AttemptExecutionOfCustomHttpGet(TableauServerSignIn onlineLogin, string customCommand)
    {
        _statusLog.AddStatusHeader("GET request: " + customCommand);
        var customGetRequest = new SendPostLogInCommand(_onlineUrls, onlineLogin, customCommand);

        try
        {
            var customResult = customGetRequest.ExecuteRequest();
            _statusLog.AddStatus("GET result: " + customResult);
        }
        catch (Exception exCustomCommand)
        {
            _statusLog.AddError("Error during custom GET, " + exCustomCommand.ToString());
        }
    }
    /// <summary>
    /// Attempt to log any detailed information we find about the failed web request
    /// </summary>
    /// <param name="webException"></param>
    /// <param name="onlineStatusLog"></param>
    private static void AttemptToLogWebException(WebException webException, string description, TaskStatusLogs onlineStatusLog)
    {
        if(onlineStatusLog == null) return; //No logger? nothing to do

        try
        {
            if(string.IsNullOrWhiteSpace(description))
            {
                description = "web request failed";
            }
            var response = webException.Response;
            var responseText = GetWebResponseAsText(response);
            response.Close();
            if(responseText == null) responseText = "";

            onlineStatusLog.AddError(description +  ": " + webException.Message + "\r\n" + responseText + "\r\n");
        }
        catch (Exception ex)
        {
            onlineStatusLog.AddError("Error in web request exception: " + ex.Message);
            return;
        }
    }
Example #21
0
    /// <summary>
    /// Remaps necesary attributes inside of the datasource->connection node to point to a new server
    /// </summary>
    /// <param name="xDSourceConnection"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapSingleDataServerConnectionNode(XmlNode xNodeDatasource, ITableauServerSiteInfo serverMapInfo, TaskStatusLogs statusLog)
    {
        //Get the XML sub mode we need
        var xNodeConnection = xNodeDatasource.SelectSingleNode("connection");

        if (xNodeConnection == null)
        {
            statusLog.AddError("Workbook remapper, no 'connection' node found");
            return;
        }
        //====================================================================================
        //PORT NUMBER
        //====================================================================================
        var attrPort = xNodeConnection.Attributes["port"];

        if (attrPort != null)
        {
            if (serverMapInfo.Protocol == ServerProtocol.http)
            {
                attrPort.Value = "80";
            }
            else if (serverMapInfo.Protocol == ServerProtocol.https)
            {
                attrPort.Value = "443";
            }
            else
            {
                statusLog.AddError("Workbook remapper, unknown protocol");
            }
        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'port'");
        }

        //====================================================================================
        //Server name
        //====================================================================================
        var attrServer = xNodeConnection.Attributes["server"];

        if (attrServer != null)
        {
            attrServer.Value = serverMapInfo.ServerName;
        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'server'");
        }

        //====================================================================================
        //Channel
        //====================================================================================
        var attrChannel = xNodeConnection.Attributes["channel"];

        if (attrChannel != null)
        {
            if (serverMapInfo.Protocol == ServerProtocol.http)
            {
                attrChannel.Value = "http";
            }
            else if (serverMapInfo.Protocol == ServerProtocol.https)
            {
                attrChannel.Value = "https";
            }
            else
            {
                statusLog.AddError("Workbook remapper, unknown protocol");
            }
        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'channel'");
        }
    }
Example #22
0
    /// <summary>
    /// Remaps necesary attributes inside of the datasource->connection node to point to a new server
    /// </summary>
    /// <param name="xDSourceConnection"></param>
    /// <param name="serverMapInfo"></param>
    /// <param name="statusLog"></param>
    private static void RemapSingleDataServerConnectionNode(XmlNode xNodeDatasource, ITableauServerSiteInfo serverMapInfo, TaskStatusLogs statusLog)
    {
        //Get the XML sub mode we need
        var xNodeConnection = xNodeDatasource.SelectSingleNode("connection");
        if(xNodeConnection == null)
        {
            statusLog.AddError("Workbook remapper, no 'connection' node found");
            return;
        }
        //====================================================================================
        //PORT NUMBER
        //====================================================================================
        var attrPort = xNodeConnection.Attributes["port"];
        if(attrPort != null)
        {
            if(serverMapInfo.Protocol == ServerProtocol.http)
            {
                attrPort.Value = "80";
            }
            else if (serverMapInfo.Protocol == ServerProtocol.https)
            {
                attrPort.Value = "443";
            }
            else
            {
                statusLog.AddError("Workbook remapper, unknown protocol");
            }
        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'port'");
        }

        //====================================================================================
        //Server name
        //====================================================================================
        var attrServer = xNodeConnection.Attributes["server"];
        if (attrServer != null)
        {
            attrServer.Value = serverMapInfo.ServerName;
        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'server'");
        }

        //====================================================================================
        //Channel
        //====================================================================================
        var attrChannel = xNodeConnection.Attributes["channel"];
        if (attrChannel != null)
        {
            if (serverMapInfo.Protocol == ServerProtocol.http)
            {
                attrChannel.Value = "http";
            }
            else if (serverMapInfo.Protocol == ServerProtocol.https)
            {
                attrChannel.Value = "https";
            }
            else
            {
                statusLog.AddError("Workbook remapper, unknown protocol");
            }

        }
        else
        {
            statusLog.AddError("Workbook remapper, missing attribute 'channel'");
        }
    }
Example #23
0
        /// <summary>
        /// Generate a maniefest file based on the current Online site
        /// </summary>
        /// <param name="statusLogs"></param>
        /// <param name="pathSecrets"></param>
        /// <param name="pathOutputFile"></param>
        /// <param name="ignoreAllUsersGroup">(recommend TRUE) If false, the manifest file will contain the "all users" group</param>
        private void GenerateManifestFromOnlineSite(
            TaskStatusLogs statusLogs,
            string pathSecrets,
            string pathOutputFile,
            bool ignoreAllUsersGroup)
        {
            var pathOutputs = Path.GetDirectoryName(pathOutputFile);

            ProvisionConfigSiteAccess secretsConfig;

            //===========================================================================================
            //Get the sign in information
            //===========================================================================================
            try
            {
                //Load the config from the files
                secretsConfig = new ProvisionConfigSiteAccess(pathSecrets);
            }
            catch (Exception exSignInConfig)
            {
                statusLogs.AddError("Error loading sign in config file");
                throw new Exception("1012-327: Error parsing sign in config, " + exSignInConfig.Message);
            }


            //===========================================================================================
            //Create a place for out output files
            //===========================================================================================
            FileIOHelper.CreatePathIfNeeded(pathOutputs);


            var provisionSettings = ProvisionConfigExternalDirectorySync.FromDefaults();

            //===========================================================================================
            //Download all the data we need from the Tableau Online site
            //===========================================================================================
            statusLogs.AddStatusHeader("Retrieving information from Tableau");
            UpdateStatusText(statusLogs);
            var tableauDownload = new TableauProvisionDownload(
                secretsConfig,
                this,
                statusLogs,
                ignoreAllUsersGroup);

            try
            {
                tableauDownload.Execute();
            }
            catch (Exception exTableauDownload)
            {
                statusLogs.AddError("Error retrieving data from Tableau");
                throw new Exception("813-0148: Error in Tableau Download, " + exTableauDownload.Message);
            }


            //===========================================================================================
            //Write the provisioning manifest out to a file
            //===========================================================================================
            statusLogs.AddStatusHeader("Writing out manifest file for Tableau provisioning");
            UpdateStatusText(statusLogs);
            var outputProvisioningRoles = tableauDownload.ProvisioningManifestResults;

            try
            {
                outputProvisioningRoles.GenerateProvisioningManifestFile(pathOutputFile, provisionSettings);
            }
            catch (Exception exWriteProvisioningManifest)
            {
                statusLogs.AddError("Error creating provisioning manifest");
                throw new Exception("1012-252: Error writing provisioning manifest, " + exWriteProvisioningManifest.Message);
            }
        }
Example #24
0
        /// <summary>
        /// Run the provisioning pulling from AzureAD
        /// </summary>
        /// <param name="pathSecrets"></param>
        /// <param name="pathProvisionPlan"></param>
        private void ProvisionFromAzureAd(
            TaskStatusLogs statusLogs,
            string pathSecrets,
            string pathProvisionPlan,
            bool deployToTableauTarget,
            string pathOutputs)
        {
            //===========================================================================================
            //Create a place for out output files
            //===========================================================================================
            FileIOHelper.CreatePathIfNeeded(pathOutputs);

            AzureAdConfig configSignInAzure;
            ProvisionConfigExternalDirectorySync configGroupsMapping;

            //===========================================================================================
            //Get the sign in information
            //===========================================================================================
            try
            {
                //Load the config from the files
                configSignInAzure = new AzureAdConfig(pathSecrets);
            }
            catch (Exception exSignInConfig)
            {
                statusLogs.AddError("Error loading sign in config file. Error: " + exSignInConfig.Message);
                throw new Exception("813-1212: Error parsing sign in config, " + exSignInConfig.Message);
            }

            //===========================================================================================
            //Get the Groups/Roles mapping information
            //===========================================================================================
            try
            {
                configGroupsMapping = new ProvisionConfigExternalDirectorySync(pathProvisionPlan);
            }
            catch (Exception exGroupsMapping)
            {
                statusLogs.AddError("Error loading sync groups provisioning file. Error: " + exGroupsMapping.Message);
                throw new Exception("813-1214: Error parsing sync groups, " + exGroupsMapping.Message);
            }

            //===========================================================================================
            //Download all the data we need from Azure
            //===========================================================================================
            statusLogs.AddStatusHeader("Retrieving information from Azure AD");
            UpdateStatusText(statusLogs);
            var azureDownload = new AzureDownload(configSignInAzure, configGroupsMapping, this, statusLogs, null);

            try
            {
                azureDownload.Execute();
                //Sanity test
                IwsDiagnostics.Assert(azureDownload.IsExecuteComplete.Value, "813-834: Internal error. Async work still running");
            }
            catch (Exception exAzureDownload)
            {
                statusLogs.AddError("Error retrieving data from Azure AD. Error: " + exAzureDownload.Message);
                throw new Exception("813-0148: Error in Azure Download, " + exAzureDownload.Message);
            }

            //===========================================================================================
            //Write the provisioning manifest out to an intermediary file
            //===========================================================================================
            statusLogs.AddStatusHeader("Writing out manifest file for Tableau provisioning");
            UpdateStatusText(statusLogs);
            var    outputProvisioningRoles = azureDownload.ProvisioningManifestResults;
            string provisioningManifest    = Path.Combine(pathOutputs, "ProvisioningManifest.xml");

            try
            {
                outputProvisioningRoles.GenerateProvisioningManifestFile(provisioningManifest, configGroupsMapping);
            }
            catch (Exception exWriteProvisioningManifest)
            {
                statusLogs.AddError("Error creating provisioning manifest. Error: " + exWriteProvisioningManifest.Message);
                throw new Exception("813-739: Error writing provisioning manifest, " + exWriteProvisioningManifest.Message);
            }


            //=================================================================================================
            //See if this is a test run, or whether we want to actually deploy the provisioning
            //=================================================================================================
            if (deployToTableauTarget)
            {
                //===========================================================================================
                //Provision the Tableau site using the manifest file we just created
                //===========================================================================================
                statusLogs.AddStatusHeader("Provision Tableau site using generated manifest file");
                UpdateStatusText(statusLogs);
                try
                {
                    ProvisionFromFileManifest(statusLogs, pathSecrets, provisioningManifest, pathOutputs);
                }
                catch (Exception exProvisionSite)
                {
                    statusLogs.AddError("Error provisioning Tableau Online site. Error: " + exProvisionSite.Message);
                    throw new Exception("814-353: Error provisioning Tableau Online site, " + exProvisionSite.Message);
                }
            }
            else
            {
                statusLogs.AddStatusHeader("Skipping Tableau site provisioning step (generate manifest only)");
            }
        }