private async Task DownloadProjectWorkbooksAsync(TableauProject sourceProject, TableauProject destProject) { _logger?.Debug($"Downloading workbooks for project {sourceProject.Name}"); var sourceWorkbookService = _tableauServiceFactorySource.GetService <TableauWorkbookService>(); var sourceWorkbooks = await GetProjectWorkbooksAsync( sourceProject.Id, _tableauServiceFactorySource ).ConfigureAwait(false); if (!Directory.Exists(_settingsMonitor.CurrentValue.workbookDownloadPath)) { Directory.CreateDirectory(_settingsMonitor.CurrentValue.workbookDownloadPath); } foreach (var sourceWorkbook in sourceWorkbooks.Values) { _logger?.Debug($"Downloading workbook '{sourceWorkbook.Name}'"); if (!_settingsMonitor.CurrentValue.DryRun) { var fileName = VizDatasourceService.GetValidFileName(sourceWorkbook.Name) + ".twb"; var fileInfo = await sourceWorkbookService.DownloadWorkbookAsync( sourceWorkbook.Id, _settingsMonitor.CurrentValue.workbookDownloadPath, fileName ).ConfigureAwait(false); _logger?.Debug($"Downloaded workbook '{sourceWorkbook.Name}' to '{fileInfo.FullName}'"); } } _logger?.Debug($"Downloaded workbooks for project {sourceProject.Name}"); }
private async Task <TableauWorkbook> MigrateWorkbookAsync( string sourceWorkbookId, string destProjectId, string destUserId ) { _logger?.Debug($"Migrating workbook {sourceWorkbookId}"); var sourceWorkbookService = _tableauServiceFactorySource.GetService <TableauWorkbookService>(); var destWorkbookService = _tableauServiceFactoryDest.GetService <TableauWorkbookService>(); var sourceDatasourceService = _tableauServiceFactorySource.GetService <TableauDatasourceService>(); var destDatasourceService = _tableauServiceFactoryDest.GetService <TableauDatasourceService>(); var sourceBaseUri = new Uri(_settingsMonitor.CurrentValue.TableauApiSettingsSource.BaseUrl); var destBaseUri = new Uri(_settingsMonitor.CurrentValue.TableauApiSettingsDestination.BaseUrl); var sourceServer = sourceBaseUri.Host; var destServer = destBaseUri.Host; await _vizDatasourceService.LoadVizDatasourceReportAsync().ConfigureAwait(false); // get workbook metadata var workbook = await sourceWorkbookService.GetWorkbookAsync( sourceWorkbookId, true ).ConfigureAwait(false); _logger?.Debug($"Migrating workbook {workbook.Name}"); // reassign project and owner for import to destination workbook.Project.Id = destProjectId; workbook.Owner.Id = destUserId; // populate workbook connection info foreach (var connection in workbook.Connections) { if (connection.Type.EqualsIgnoreCase(TableauApiService.CONNECTION_TYPE_SQLPROXY)) { // published/proxy connection if (!String.IsNullOrWhiteSpace(connection.ServerAddress) && !connection.ServerAddress.EqualsIgnoreCase(sourceServer) && !connection.ServerAddress.EqualsIgnoreCase("localhost")) { throw new Exception($"Unexpected source connection server address: {connection.ServerAddress}"); } var datasource = await sourceDatasourceService.GetDatasourceAsync( connection.Datasource.Id, true ).ConfigureAwait(false); var destDatasource = await destDatasourceService.FindDatasourceAsync( datasource.Name, true ).ConfigureAwait(false); // get datasource credentials from viz datasource report (csv) var vizDatasource = _vizDatasourceService.GetVizDatasource( _vizDatasourceService.GetValidName(datasource.Name.Trim()) ); if (destDatasource != null) { _logger?.Debug($"Datasource found in destination: {destDatasource.Id}"); } if (vizDatasource == null) { _logger?.Warning( "Viz datasource not found for sqlproxy workbook connection {0}, skipping: {1} ({2})", connection.Id, _vizDatasourceService.GetValidName(datasource.Name), datasource.Name ); continue; } if ( destDatasource == null || destDatasource.Project?.Id != destProjectId || !destDatasource.Connections.Any(c => (c.ServerAddress ?? "").EqualsIgnoreCase(destServer)) && !destDatasource.Connections.Any( c => (c.Username ?? "").EqualsIgnoreCase(vizDatasource.VizConnectionDetail.Username) ) ) { // source datasource doesn't exist in destination, publish // reassign project for import to destination datasource.Project.Id = destProjectId; // populate datasource connection credentials datasource.ConnectionCredentials = new TableauConnectionCredentials() { Username = vizDatasource.VizConnectionDetail.Username, Password = vizDatasource.VizConnectionDetail.Password, Embed = true }; _logger?.Debug("Publish datasource:"); _logger?.Debug(JsonConvert.SerializeObject(datasource)); // get datasource file data var datasourceBytes = _vizDatasourceService.GetVizDatasourceFile(vizDatasource.Name); datasourceBytes.ContentType = "application/octet-stream"; datasourceBytes.ContentDispositionName = "tableau_datasource"; if (!_settingsMonitor.CurrentValue.DryRun) { destDatasource = await destDatasourceService.PublishDatasourceAsync( datasource, datasourceBytes ).ConfigureAwait(false); // allow Tableau api to catch up to db changes await Task.Delay(1000).ConfigureAwait(false); } } connection.ConnectionCredentials = new TableauConnectionCredentials() { Username = vizDatasource.VizConnectionDetail.Username, Password = vizDatasource.VizConnectionDetail.Password, Embed = true }; connection.Datasource = destDatasource; connection.ServerAddress = destServer; } else if (!String.IsNullOrWhiteSpace(connection.Username)) { // embedded connection.ConnectionCredentials = new TableauConnectionCredentials() { Username = connection.Username, Password = GetConnectionPassword(connection.Username), Embed = true }; } else { throw new Exception("Workbook connection not sqlproxy but missing username"); } } // get workbook file data var workbookBytes = await sourceWorkbookService.DownloadWorkbookBytesAsync( workbook.Id ).ConfigureAwait(false); workbookBytes.ContentType = "application/octet-stream"; workbookBytes.ContentDispositionName = "tableau_workbook"; var savePath = Path.Combine( _settingsMonitor.CurrentValue.workbookDownloadPath, VizDatasourceService.GetValidFileName(workbookBytes.FilePath).Replace(".twb", "_publish.twb") ); workbookBytes.Bytes = Encoding.UTF8.GetBytes( UpdateWorkbookPublishedDatasourceConnections( Encoding.UTF8.GetString(workbookBytes.Bytes), sourceServer, destServer ) ); workbookBytes.Bytes = Encoding.UTF8.GetBytes( UpdateWorkbookPublishedDatasourceConnections( Encoding.UTF8.GetString(workbookBytes.Bytes), "localhost", destServer ) ); _logger?.Debug($"Saving copy of workbook to {savePath}"); File.WriteAllBytes(savePath, workbookBytes.Bytes); _logger?.Debug($"Publishing workbook {workbook.Name}"); return(!_settingsMonitor.CurrentValue.DryRun ? await destWorkbookService.PublishWorkbookAsync(workbook, workbookBytes).ConfigureAwait(false) : null); }