Merge branch 'master' of https://github.com/xenserver/xenadmin into development
# Conflicts: # Branding/Branding.resx # Branding/HomePage.mht # Branding/HomePage.zh-CN.mht # Branding/Images/000_XenCenterAlerts_h32bit_24.png # Branding/Images/DlgBmp.bmp # Branding/Images/XS.png # Branding/Images/about_box_graphic_423x79.png # Branding/Images/alerts_32.png # Branding/Images/splash.bmp # Branding/Images/upsell_16.png # Branding/Images/wizard_background.png # CFUValidator/CFUValidator.csproj # Jenkinsfile # LICENSE # MAINTAINERS # README.md # WixInstaller/XenCenter.wxs # WixInstaller/branding.wxi # WixInstaller/codepagechange.vbs # WixInstaller/en-us.wxl # WixInstaller/ja-jp.wxl # WixInstaller/wix_src.patch # WixInstaller/zh-cn.wxl # XenAdmin.sln # XenAdmin/Commands/Controls/ContextMenuBuilder.cs # XenAdmin/Commands/Controls/MigrateVMToolStripMenuItem.cs # XenAdmin/Commands/Controls/VMLifeCycleToolStripMenuItem.cs # XenAdmin/Commands/CopyTemplateCommand.cs # XenAdmin/Commands/CopyVMCommand.cs # XenAdmin/Commands/CrossPoolCopyVMCommand.cs # XenAdmin/Commands/CrossPoolMigrateCommand.cs # XenAdmin/Commands/CrossPoolMoveVMCommand.cs # XenAdmin/Commands/DragDropCrossPoolMoveHaltedVMCommand.cs # XenAdmin/Commands/DragDropMigrateVMCommand.cs # XenAdmin/Commands/MoveVMCommand.cs # XenAdmin/ConsoleView/VNCTabView.cs # XenAdmin/Core/Updates.cs # XenAdmin/Dialogs/AboutDialog.resx # XenAdmin/Dialogs/LegalNoticesDialog.cs # XenAdmin/Dialogs/WarningDialogs/LicenseWarningDialog.ja.resx # XenAdmin/Dialogs/WarningDialogs/LicenseWarningDialog.resx # XenAdmin/Dialogs/WarningDialogs/LicenseWarningDialog.zh-CN.resx # XenAdmin/Help/HelpManager.cs # XenAdmin/Images.cs # XenAdmin/MainWindow.Designer.cs # XenAdmin/MainWindow.cs # XenAdmin/MainWindow.ja.resx # XenAdmin/MainWindow.resx # XenAdmin/MainWindow.zh-CN.resx # XenAdmin/Properties/Resources.Designer.cs # XenAdmin/Properties/Settings.Designer.cs # XenAdmin/Properties/Settings.settings # XenAdmin/SettingsPanels/BootOptionsEditPage.cs # XenAdmin/TabPages/GeneralTabPage.Designer.cs # XenAdmin/TabPages/GeneralTabPage.cs # XenAdmin/TabPages/GeneralTabPage.resx # XenAdmin/VNC/VNCException.cs # XenAdmin/Wizards/CrossPoolMigrateWizard/CrossPoolMigrateDestinationPage.cs # XenAdmin/Wizards/CrossPoolMigrateWizard/CrossPoolMigrateWizard.cs # XenAdmin/Wizards/CrossPoolMigrateWizard/Filters/CrossPoolMigrateCanMigrateFilter.cs # XenAdmin/Wizards/NewNetworkWizard_Pages/NetWTypeSelect.cs # XenAdmin/Wizards/NewSRWizard.cs # XenAdmin/Wizards/NewSRWizard_Pages/Frontends/LVMoISCSI.cs # XenAdmin/XenAdmin.csproj # XenAdmin/app.config # XenAdminTests/ArchiveTests/ArchiveFactoryTests.cs # XenAdminTests/ArchiveTests/ArchiveIteratorTests.cs # XenAdminTests/ArchiveTests/ArchiveWriterTests.cs # XenAdminTests/ArchiveTests/ThirdPartyArchiveWriterTests.cs # XenAdminTests/CompressionTests/CompressionFactoryTests.cs # XenAdminTests/CompressionTests/ThirdPartyCompressionStreamTests.cs # XenAdminTests/HealthCheckTests/RequestUploadTaskTests.cs # XenAdminTests/UnitTests/CPUMaskingTest.cs # XenAdminTests/UnitTests/TimeUtilTests.cs # XenAdminTests/UnitTests/WlbTests/WlbPoolConfigurationTests.cs # XenAdminTests/UnitTests/WlbTests/WlbScheduledTaskTests.cs # XenAdminTests/UnitTests/WlbTests/WlbScheduledTasksTests.cs # XenAdminTests/XenAdminTests.csproj # XenModel/Actions/HealthCheck/GetHealthCheckAnalysisResultAction.cs # XenModel/Actions/HealthCheck/HealthCheckAuthenticationAction.cs # XenModel/Actions/HealthCheck/UploadServerStatusReportAction.cs # XenModel/Actions/HealthCheck/XenServerHealthCheckUpload.cs # XenModel/Actions/VM/ImportVmAction.cs # XenModel/Actions/VM/VMCrossPoolMigrateAction.cs # XenModel/Actions/VM/VMPauseAction.cs # XenModel/FriendlyNames.Designer.cs # XenModel/FriendlyNames.ja.resx # XenModel/FriendlyNames.resx # XenModel/FriendlyNames.zh-CN.resx # XenModel/HealthCheckSettings.cs # XenModel/InvisibleMessages.Designer.cs # XenModel/InvisibleMessages.ja.resx # XenModel/InvisibleMessages.resx # XenModel/InvisibleMessages.zh-CN.resx # XenModel/Messages.Designer.cs # XenModel/Messages.ja.resx # XenModel/Messages.resx # XenModel/Messages.zh-CN.resx # XenModel/SshConsole.cs # XenModel/Utils/Helpers.cs # XenModel/XenAPI-Extensions/SR.cs # XenModel/XenAPI/ApiVersion.cs # XenModel/XenModel.csproj # XenServerHealthCheck/Registry.cs # scripts/check_copyright.ps1 # scripts/check_i18n.ps1 # scripts/check_spelling.ps1 # scripts/deps-map.json # scripts/dictionary.txt # scripts/download_hotfixes.ps1 # scripts/download_packages.ps1 # scripts/hotfix-map.json # splash/util.h # xe/Xe.csproj # xe/app.manifest
3
.gitignore
vendored
@ -27,6 +27,7 @@ Thumbs.db
|
||||
|
||||
packages/*
|
||||
!packages/DOTNET_BUILD_LOCATION
|
||||
Branding/Hotfixes/*
|
||||
|
||||
_ReSharper.*/
|
||||
*.opensdf
|
||||
@ -40,3 +41,5 @@ ServiceFabricBackup/
|
||||
|
||||
.vs
|
||||
.vscode
|
||||
|
||||
vim.exe.stackdump
|
||||
|
@ -1,45 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
File encoded as ISO-8859-1
|
||||
Blueprint CSS Framework 1.0.1
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See src/LICENSE for more info.
|
||||
|
||||
number of columns:24
|
||||
column width:30
|
||||
gutter width:10
|
||||
total width:950
|
||||
row height:18 px
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
/* ie.css */
|
||||
html {
|
||||
overflow: auto;
|
||||
}
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
.container {
|
||||
text-align: left;
|
||||
}
|
||||
* html .column,
|
||||
* html [class^="span-"],
|
||||
* html [class*=" span- "] {
|
||||
display: inline;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
.clearfix, .container {
|
||||
display: inline-block;
|
||||
}
|
||||
* html .clearfix, * html .container {
|
||||
height: 1%;
|
||||
}
|
||||
/* fix opacity for tagline fonts */
|
||||
p.cx-tagline span{
|
||||
display: inline-block;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=69)"; /* IE 8 */
|
||||
filter: alpha(opacity=69); /* IE 5-7 */
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
File encoded as ISO-8859-1
|
||||
Blueprint CSS Framework 1.0.1
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See src/LICENSE for more info.
|
||||
|
||||
number of columns:24
|
||||
column width:30
|
||||
gutter width:10
|
||||
total width:950
|
||||
row height:18 px
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
/* print.css */
|
||||
body {
|
||||
line-height: 1.5;
|
||||
font-family: citrixsans-regular, "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
color: #000;
|
||||
background: none;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.container {
|
||||
background: none;
|
||||
}
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
p img.top {
|
||||
margin-top: 0;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
a:link, a:visited {
|
||||
background: transparent;
|
||||
font-weight: 700;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:link:after, a:visited:after {
|
||||
content: " (" attr(href) ")";
|
||||
font-size: 90%;
|
||||
}
|
@ -1,519 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
File encoded as ISO-8859-1
|
||||
Blueprint CSS Framework 1.0.1
|
||||
http://blueprintcss.org
|
||||
|
||||
* Copyright (c) 2007-Present. See src/LICENSE for more info.
|
||||
|
||||
number of columns:24
|
||||
column width:30
|
||||
gutter width:10
|
||||
total width:950
|
||||
row height:18 px
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* reset.css */
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
body, div, span, object, p, a, abbr, em, img, q, ol, ul, li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
body {
|
||||
line-height: 1.5;
|
||||
background: #fff;
|
||||
}
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* typography.css */
|
||||
html {
|
||||
font-size: 100.01%;
|
||||
}
|
||||
body {
|
||||
font-size: 75%;
|
||||
color: #fff;
|
||||
background: #fff;
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.left {
|
||||
float: left !important;
|
||||
}
|
||||
p .left {
|
||||
margin: 1.5em 1.5em 1.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
.right {
|
||||
float: right !important;
|
||||
}
|
||||
p .right {
|
||||
margin: 1.5em 0 1.5em 1.5em;
|
||||
padding: 0;
|
||||
}
|
||||
a:focus, a:hover {
|
||||
color: #5F67B5;
|
||||
}
|
||||
a {
|
||||
color: #5F67B5;
|
||||
text-decoration: underline;
|
||||
}
|
||||
li ul, li ol {
|
||||
margin: 0;
|
||||
}
|
||||
ul, ol {
|
||||
margin: 0 1.5em 1.5em 0;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.first {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.last {
|
||||
margin-right: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.top {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.bottom {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
/* grid.css */
|
||||
.container {
|
||||
width: 750px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.showgrid {
|
||||
background: url(../media/grid.png);
|
||||
}
|
||||
.column, [class^="span-"],
|
||||
.column, [class*=" span- "] {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
.span-1 {
|
||||
width: 30px;
|
||||
}
|
||||
.span-2 {
|
||||
width: 70px;
|
||||
}
|
||||
.span-3 {
|
||||
width: 110px;
|
||||
}
|
||||
.span-4 {
|
||||
width: 150px;
|
||||
}
|
||||
.span-5 {
|
||||
width: 190px;
|
||||
}
|
||||
.span-6 {
|
||||
width: 230px;
|
||||
}
|
||||
.span-7 {
|
||||
width: 270px;
|
||||
}
|
||||
.span-8 {
|
||||
width: 310px;
|
||||
}
|
||||
.span-9 {
|
||||
width: 350px;
|
||||
}
|
||||
.span-10 {
|
||||
width: 390px;
|
||||
}
|
||||
.span-11 {
|
||||
width: 430px;
|
||||
}
|
||||
.span-12 {
|
||||
width: 470px;
|
||||
}
|
||||
.span-13 {
|
||||
width: 510px;
|
||||
}
|
||||
.span-14 {
|
||||
width: 550px;
|
||||
}
|
||||
.span-15 {
|
||||
width: 590px;
|
||||
}
|
||||
.span-16 {
|
||||
width: 630px;
|
||||
}
|
||||
.span-17 {
|
||||
width: 670px;
|
||||
}
|
||||
.span-18 {
|
||||
width: 710px;
|
||||
}
|
||||
.span-19 {
|
||||
width: 750px;
|
||||
}
|
||||
.span-20 {
|
||||
width: 790px;
|
||||
}
|
||||
.span-21 {
|
||||
width: 830px;
|
||||
}
|
||||
.span-22 {
|
||||
width: 870px;
|
||||
}
|
||||
.span-23 {
|
||||
width: 910px;
|
||||
}
|
||||
.span-24 {
|
||||
width: 950px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.append-1 {
|
||||
padding-right: 20px;
|
||||
}
|
||||
.append-2 {
|
||||
padding-right: 80px;
|
||||
}
|
||||
.append-3 {
|
||||
padding-right: 120px;
|
||||
}
|
||||
.append-4 {
|
||||
padding-right: 160px;
|
||||
}
|
||||
.append-5 {
|
||||
padding-right: 200px;
|
||||
}
|
||||
.append-6 {
|
||||
padding-right: 240px;
|
||||
}
|
||||
.append-7 {
|
||||
padding-right: 280px;
|
||||
}
|
||||
.append-8 {
|
||||
padding-right: 320px;
|
||||
}
|
||||
.append-9 {
|
||||
padding-right: 360px;
|
||||
}
|
||||
.append-10 {
|
||||
padding-right: 400px;
|
||||
}
|
||||
.append-11 {
|
||||
padding-right: 440px;
|
||||
}
|
||||
.append-12 {
|
||||
padding-right: 480px;
|
||||
}
|
||||
.append-13 {
|
||||
padding-right: 520px;
|
||||
}
|
||||
.append-14 {
|
||||
padding-right: 560px;
|
||||
}
|
||||
.append-15 {
|
||||
padding-right: 600px;
|
||||
}
|
||||
.append-16 {
|
||||
padding-right: 640px;
|
||||
}
|
||||
.append-17 {
|
||||
padding-right: 680px;
|
||||
}
|
||||
.append-18 {
|
||||
padding-right: 720px;
|
||||
}
|
||||
.append-19 {
|
||||
padding-right: 760px;
|
||||
}
|
||||
.append-20 {
|
||||
padding-right: 800px;
|
||||
}
|
||||
.append-21 {
|
||||
padding-right: 840px;
|
||||
}
|
||||
.append-22 {
|
||||
padding-right: 880px;
|
||||
}
|
||||
.append-23 {
|
||||
padding-right: 920px;
|
||||
}
|
||||
.prepend-1 {
|
||||
padding-left: 40px;
|
||||
}
|
||||
.prepend-2 {
|
||||
padding-left: 80px;
|
||||
}
|
||||
.prepend-3 {
|
||||
padding-left: 120px;
|
||||
}
|
||||
.prepend-4 {
|
||||
padding-left: 160px;
|
||||
}
|
||||
.prepend-5 {
|
||||
padding-left: 200px;
|
||||
}
|
||||
.prepend-6 {
|
||||
padding-left: 240px;
|
||||
}
|
||||
.prepend-7 {
|
||||
padding-left: 280px;
|
||||
}
|
||||
.prepend-8 {
|
||||
padding-left: 320px;
|
||||
}
|
||||
.prepend-9 {
|
||||
padding-left: 360px;
|
||||
}
|
||||
.prepend-10 {
|
||||
padding-left: 400px;
|
||||
}
|
||||
.prepend-11 {
|
||||
padding-left: 440px;
|
||||
}
|
||||
.prepend-12 {
|
||||
padding-left: 480px;
|
||||
}
|
||||
.prepend-13 {
|
||||
padding-left: 520px;
|
||||
}
|
||||
.prepend-14 {
|
||||
padding-left: 560px;
|
||||
}
|
||||
.prepend-15 {
|
||||
padding-left: 600px;
|
||||
}
|
||||
.prepend-16 {
|
||||
padding-left: 640px;
|
||||
}
|
||||
.prepend-17 {
|
||||
padding-left: 680px;
|
||||
}
|
||||
.prepend-18 {
|
||||
padding-left: 720px;
|
||||
}
|
||||
.prepend-19 {
|
||||
padding-left: 760px;
|
||||
}
|
||||
.prepend-20 {
|
||||
padding-left: 800px;
|
||||
}
|
||||
.prepend-21 {
|
||||
padding-left: 840px;
|
||||
}
|
||||
.prepend-22 {
|
||||
padding-left: 880px;
|
||||
}
|
||||
.prepend-23 {
|
||||
padding-left: 920px;
|
||||
}
|
||||
.border {
|
||||
padding-right: 4px;
|
||||
margin-right: 5px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
.colborder {
|
||||
padding-right: 24px;
|
||||
margin-right: 25px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
.pull-1 {
|
||||
margin-left: -40px;
|
||||
}
|
||||
.pull-2 {
|
||||
margin-left: -80px;
|
||||
}
|
||||
.pull-3 {
|
||||
margin-left: -120px;
|
||||
}
|
||||
.pull-4 {
|
||||
margin-left: -160px;
|
||||
}
|
||||
.pull-5 {
|
||||
margin-left: -200px;
|
||||
}
|
||||
.pull-6 {
|
||||
margin-left: -240px;
|
||||
}
|
||||
.pull-7 {
|
||||
margin-left: -280px;
|
||||
}
|
||||
.pull-8 {
|
||||
margin-left: -320px;
|
||||
}
|
||||
.pull-9 {
|
||||
margin-left: -360px;
|
||||
}
|
||||
.pull-10 {
|
||||
margin-left: -400px;
|
||||
}
|
||||
.pull-11 {
|
||||
margin-left: -440px;
|
||||
}
|
||||
.pull-12 {
|
||||
margin-left: -480px;
|
||||
}
|
||||
.pull-13 {
|
||||
margin-left: -520px;
|
||||
}
|
||||
.pull-14 {
|
||||
margin-left: -560px;
|
||||
}
|
||||
.pull-15 {
|
||||
margin-left: -600px;
|
||||
}
|
||||
.pull-16 {
|
||||
margin-left: -640px;
|
||||
}
|
||||
.pull-17 {
|
||||
margin-left: -680px;
|
||||
}
|
||||
.pull-18 {
|
||||
margin-left: -720px;
|
||||
}
|
||||
.pull-19 {
|
||||
margin-left: -760px;
|
||||
}
|
||||
.pull-20 {
|
||||
margin-left: -800px;
|
||||
}
|
||||
.pull-21 {
|
||||
margin-left: -840px;
|
||||
}
|
||||
.pull-22 {
|
||||
margin-left: -880px;
|
||||
}
|
||||
.pull-23 {
|
||||
margin-left: -920px;
|
||||
}
|
||||
.pull-24 {
|
||||
margin-left: -960px;
|
||||
}
|
||||
[class^="pull-"],
|
||||
[class*=" pull- "] {
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
.push-1 {
|
||||
margin: 0 -40px 1.5em 40px;
|
||||
}
|
||||
.push-2 {
|
||||
margin: 0 -80px 1.5em 80px;
|
||||
}
|
||||
.push-3 {
|
||||
margin: 0 -120px 1.5em 120px;
|
||||
}
|
||||
.push-4 {
|
||||
margin: 0 -160px 1.5em 160px;
|
||||
}
|
||||
.push-5 {
|
||||
margin: 0 -200px 1.5em 200px;
|
||||
}
|
||||
.push-6 {
|
||||
margin: 0 -240px 1.5em 240px;
|
||||
}
|
||||
.push-7 {
|
||||
margin: 0 -280px 1.5em 280px;
|
||||
}
|
||||
.push-8 {
|
||||
margin: 0 -320px 1.5em 320px;
|
||||
}
|
||||
.push-9 {
|
||||
margin: 0 -360px 1.5em 360px;
|
||||
}
|
||||
.push-10 {
|
||||
margin: 0 -400px 1.5em 400px;
|
||||
}
|
||||
.push-11 {
|
||||
margin: 0 -440px 1.5em 440px;
|
||||
}
|
||||
.push-12 {
|
||||
margin: 0 -480px 1.5em 480px;
|
||||
}
|
||||
.push-13 {
|
||||
margin: 0 -520px 1.5em 520px;
|
||||
}
|
||||
.push-14 {
|
||||
margin: 0 -560px 1.5em 560px;
|
||||
}
|
||||
.push-15 {
|
||||
margin: 0 -600px 1.5em 600px;
|
||||
}
|
||||
.push-16 {
|
||||
margin: 0 -640px 1.5em 640px;
|
||||
}
|
||||
.push-17 {
|
||||
margin: 0 -680px 1.5em 680px;
|
||||
}
|
||||
.push-18 {
|
||||
margin: 0 -720px 1.5em 720px;
|
||||
}
|
||||
.push-19 {
|
||||
margin: 0 -760px 1.5em 760px;
|
||||
}
|
||||
.push-20 {
|
||||
margin: 0 -800px 1.5em 800px;
|
||||
}
|
||||
.push-21 {
|
||||
margin: 0 -840px 1.5em 840px;
|
||||
}
|
||||
.push-22 {
|
||||
margin: 0 -880px 1.5em 880px;
|
||||
}
|
||||
.push-23 {
|
||||
margin: 0 -920px 1.5em 920px;
|
||||
}
|
||||
.push-24 {
|
||||
margin: 0 -960px 1.5em 960px;
|
||||
}
|
||||
[class^="push-"],
|
||||
[class*=" push- "] {
|
||||
float: left;
|
||||
position: relative;
|
||||
}
|
||||
div.prepend-top, .prepend-top {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
div.append-bottom, .append-bottom {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
.box {
|
||||
padding: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
background: #e5eCf9;
|
||||
}
|
||||
.clearfix:after, .container:after {
|
||||
content: "\0020";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
.clearfix, .container {
|
||||
display: block;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/* Top Hero Section */
|
||||
.cx-hero-top,
|
||||
.cx-hero-top-bg {
|
||||
background: #5F67B5;
|
||||
height: 310px;
|
||||
}
|
||||
.cx-hero-top-bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
.cx-hero-top {
|
||||
color: #fff;
|
||||
}
|
||||
/* top hero columns */
|
||||
.cx-hero-top .inner .column {
|
||||
height: 165px;
|
||||
}
|
||||
.cx-hero-top .inner .column.left {
|
||||
padding-top: 36px;
|
||||
padding-bottom: 42px;
|
||||
}
|
||||
.cx-hero-top .inner .column.right {
|
||||
width: 127px;
|
||||
height: 165px;
|
||||
line-height: 165px;
|
||||
text-align: center;
|
||||
margin-top: 65px;
|
||||
}
|
||||
.cx-hero-top .inner .column.right img#cloudServerGraphic {
|
||||
width: 129px;
|
||||
height: 165px;
|
||||
}
|
||||
.cx-hero-top .inner .column.left img#logo-citrixHypervisor {
|
||||
display: block;
|
||||
width: 216px;
|
||||
height: 31px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
p.cx-tagline {
|
||||
font: 16px/1.3 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
color: rgba(256, 256, 256, 0.69);
|
||||
letter-spacing: 0.02em;
|
||||
margin-bottom: 32px!important;
|
||||
font-weight: 300;
|
||||
}
|
||||
/* call out list */
|
||||
ul.cx-callouts-list {
|
||||
font: 14px/1.3 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-weight:300;
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
ul.cx-callouts-list li.cx-doc-icon{
|
||||
display: block;
|
||||
height: 21px;
|
||||
line-height: 21px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: -17px;
|
||||
padding-left: 32px;
|
||||
background: transparent url(../media/icons/cx-icon-generic-doc.png) no-repeat 0 50%;
|
||||
}
|
||||
ul.cx-callouts-list li.cx-doc-icon.last{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/* start callout links */
|
||||
ul.cx-callouts-list li.cx-doc-icon a.cx-link {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
ul.cx-callouts-list li.cx-doc-icon a.cx-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul.cx-callouts-list li.cx-doc-icon ul.cx-link-list{
|
||||
list-style-type: square;
|
||||
list-style-position: inside;
|
||||
padding: 0 0 0 0;
|
||||
margin: 5px 0 0 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
/* end callout links */
|
||||
|
||||
|
||||
/* Bottom Hero Section */
|
||||
.cx-hero-bottom {
|
||||
margin:34px 0 0 0;
|
||||
padding-bottom: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
/* cards */
|
||||
.cx-hero-bottom .cx-cards {
|
||||
height: 198px;
|
||||
width: 200px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.cx-hero-bottom .cx-cards:hover {
|
||||
background-color: #f2f2f2;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.cx-hero-bottom .cx-cards.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
.cx-hero-bottom .cx-cards p {
|
||||
padding-top: 35px;
|
||||
color: #5F67B5;
|
||||
font: 14px/1.3 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
/* card icons */
|
||||
.cx-cards img {
|
||||
margin-top: 37px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
img#addServer {
|
||||
width: 55px;
|
||||
height: 66px;
|
||||
}
|
||||
img#purchaseSupport {
|
||||
width: 57px;
|
||||
height: 65px;
|
||||
}
|
||||
img#deskTopVirt {
|
||||
width: 86px;
|
||||
height: 66px;
|
||||
}
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Citrix Hypervisor</title>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/theme.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/print.css" type="text/css" media="print">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="cx-hero-top-bg">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="span-18 top cx-hero-top">
|
||||
<div class="span-16 prepend-1 append-0 inner last">
|
||||
<div class="column left span-12 first">
|
||||
<img id="logo-citrixHypervisor" src="media/logos/cx-logo-citrixHypervisor.png" alt="Citrix Hypervisor Logo"/>
|
||||
<p class="cx-tagline" title="Industry leading open source platform for cloud server and desktop virtualization">
|
||||
<span>Industry leading open source platform for cloud server<br> and desktop virtualization</span>
|
||||
</p>
|
||||
<ul class="cx-callouts-list">
|
||||
<li class="cx-doc-icon" title="Learn about using XenCenter">
|
||||
<a href="xencenter://HelpContents" class="cx-link">Learn about using XenCenter</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon" title="Network with other Citrix Hypervisor users">
|
||||
<a href="https://discussions.citrix.com/forum/101-hypervisor-formerly-xenserver/" class="cx-link">Network with other Citrix Hypervisor users</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon last" title="Community Support Partners">
|
||||
<a href="https://www.citrix.com/support" class="cx-link">Visit the Citrix Knowledge Center</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="column right span-6 last">
|
||||
<img id="cloudServerGraphic" src="media/icons/cx-cloudServerGraphic.png" alt="Cloud Server Graphic">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="span-18 cx-hero-bottom clearfix">
|
||||
<div class="column prepend-1 clearfix">
|
||||
<div class="span-6 cx-cards" title="Add a Server">
|
||||
<a class="cx-link" href="xencenter://AddServer">
|
||||
<img id="addServer" src="media/icons/cx-icon-addServer.png" alt="Add a Server">
|
||||
<p>Add a Server</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="span-6 cx-cards" title="Purchase Support">
|
||||
<a class="cx-link" href="http://www.citrix.com/xenserver/le/features">
|
||||
<img id="purchaseSupport" src="media/icons/cx-icon-purchaseSupport.png" alt="Purchase Support">
|
||||
<p>Purchase Support</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="span-6 cx-cards last" title="Try Desktop Virtualization">
|
||||
<a class="cx-link" href="http://www.citrix.com/TryXenDesktop">
|
||||
<img id="deskTopVirt" src="media/icons/cx-icon-tryVirtualization.png" alt="Try Desktop Virtualization">
|
||||
<p>Try Desktop Virtualization</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="media/icons/cx-icon-generic-doc.png" height="0" width="0">
|
||||
</body>
|
||||
</html>
|
@ -1,69 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Citrix Hypervisor</title>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/theme.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/print.css" type="text/css" media="print">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="cx-hero-top-bg">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="span-18 top cx-hero-top">
|
||||
<div class="span-16 prepend-1 append-0 inner last">
|
||||
<div class="column left span-12 first">
|
||||
<img id="logo-citrixHypervisor" src="media/logos/cx-logo-citrixHypervisor.png" alt="Citrix Hypervisor Logo">
|
||||
<p class="cx-tagline" title="業界で高く評価されているクラウド、サーバー、デスクトップの仮想化プラットフォームです。">
|
||||
<span>業界で高く評価されているクラウド サーバー<br>およびデスクトップの仮想化プラットフォームです。</span>
|
||||
</p>
|
||||
<ul class="cx-callouts-list">
|
||||
<li class="cx-doc-icon" title="XenCenter の使用について">
|
||||
<a href="xencenter://HelpContents" class="cx-link">XenCenter の使用について</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon" title="Citrix Hypervisor ユーザー ネットワーク">
|
||||
<a href="https://discussions.citrix.com/forum/101-hypervisor-formerly-xenserver/" class="cx-link">Citrix Hypervisor ユーザー ネットワーク</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon last" title="製品情報、コミュニティ、サポート、対応製品">
|
||||
<a href="https://www.citrix.com/support" class="cx-link">Citrix Knowledge Center の参照</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="column right span-6 last">
|
||||
<img id="cloudServerGraphic" src="media/icons/cx-cloudServerGraphic.png" alt="クラウド サーバーのグラフィック">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="span-18 cx-hero-bottom clearfix">
|
||||
<div class="column prepend-1 clearfix">
|
||||
<div class="span-6 cx-cards" title="サーバーの追加">
|
||||
<a class="cx-link" href="xencenter://AddServer">
|
||||
<img id="addServer" src="media/icons/cx-icon-addServer.png" alt="サーバーの追加">
|
||||
<p>サーバーの追加</p>
|
||||
</a>
|
||||
</div>
|
||||
<div title="購入サポート" class="span-6 cx-cards">
|
||||
<a class="cx-link" href="http://www.citrix.com/xenserver/le/features">
|
||||
<img id="purchaseSupport" src="media/icons/cx-icon-purchaseSupport.png" alt="購入サポート">
|
||||
<p>購入サポート</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="span-6 cx-cards last" title="デスクトップの仮想化の試行">
|
||||
<a class="cx-link" href="http://www.citrix.com/TryXenDesktop">
|
||||
<img id="deskTopVirt" src="media/icons/cx-icon-tryVirtualization.png" alt="デスクトップの仮想化の試行">
|
||||
<p>デスクトップの仮想化の試行</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="media/icons/cx-icon-generic-doc.png" height="0" width="0">
|
||||
</body>
|
||||
</html>
|
@ -1,69 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Citrix Hypervisor</title>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/theme.css" type="text/css" media="screen, projection">
|
||||
<link rel="stylesheet" href="css/print.css" type="text/css" media="print">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="cx-hero-top-bg">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="span-18 top cx-hero-top">
|
||||
<div class="span-16 prepend-1 append-0 inner last">
|
||||
<div class="column left span-12 first">
|
||||
<img id="logo-citrixHypervisor" src="media/logos/cx-logo-citrixHypervisor.png" alt="Citrix Hypervisor Logo"/>
|
||||
<p class="cx-tagline" title="业界领先的开源平台,用于实现云服务器和桌面虚拟化">
|
||||
<span>业界领先的面向云服务器和桌面虚拟化的<br>开源平台</span>
|
||||
</p>
|
||||
<ul class="cx-callouts-list">
|
||||
<li class="cx-doc-icon" title="了解如何使用 XenCenter">
|
||||
<a href="xencenter://HelpContents" class="cx-link">了解如何使用 XenCenter</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon" title="与其他 Citrix Hypervisor 用户联网">
|
||||
<a href="https://discussions.citrix.com/forum/101-hypervisor-formerly-xenserver/" class="cx-link">与其他 Citrix Hypervisor 用户联网</a>
|
||||
</li>
|
||||
<li class="cx-doc-icon last" title="社区支持合作伙伴">
|
||||
<a href="https://www.citrix.com/support" class="cx-link">访问 Citrix 知识中心</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="column right span-6 last">
|
||||
<img id="cloudServerGraphic" src="media/icons/cx-cloudServerGraphic.png" alt="云服务器图形">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="span-18 cx-hero-bottom clearfix">
|
||||
<div class="column prepend-1 clearfix">
|
||||
<div class="span-6 cx-cards" title="添加服务器">
|
||||
<a class="cx-link" href="xencenter://AddServer">
|
||||
<img id="addServer" alt="添加服务器" src="media/icons/cx-icon-addServer.png">
|
||||
<p>添加服务器</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="span-6 cx-cards" title="购买支持">
|
||||
<a class="cx-link" href="http://www.citrix.com/xenserver/le/features">
|
||||
<img id="purchaseSupport" src="media/icons/cx-icon-purchaseSupport.png" alt="购买支持">
|
||||
<p>购买支持</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="span-6 cx-cards last" title="试用桌面虚拟化">
|
||||
<a class="cx-link" href="http://www.citrix.com/TryXenDesktop">
|
||||
<img id="deskTopVirt" src="media/icons/cx-icon-tryVirtualization.png" alt="试用桌面虚拟化">
|
||||
<p>试用桌面虚拟化</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="media/icons/cx-icon-generic-doc.png" height="0" width="0">
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 648 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 964 B |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 264 KiB |
Before Width: | Height: | Size: 995 B |
0
Branding/Images/wizard_background.png
Executable file → Normal file
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@ -1,67 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) Citrix Systems, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms,
|
||||
# with or without modification, are permitted provided
|
||||
# that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above
|
||||
# copyright notice, this list of conditions and the
|
||||
# following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the
|
||||
# following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
#==============================================================
|
||||
#Micro version override - please keep at the top of the script
|
||||
#==============================================================
|
||||
#Set and uncomment this to override the 3rd value of the product number
|
||||
#normally fetched from branding
|
||||
#
|
||||
#PRODUCT_MICRO_VERSION_OVERRIDE=<My override value here>
|
||||
|
||||
# bring versions from the server branding repo
|
||||
ROOT="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
|
||||
|
||||
TOPLEVEL_VERSIONS=${ROOT}/branding.git/xenserver/toplevel-versions
|
||||
TOPLEVEL_BRANDING=${ROOT}/branding.git/xenserver/toplevel-branding
|
||||
|
||||
BRANDING_COMPANY_NAME_LEGAL=$(cat ${TOPLEVEL_BRANDING} | grep -F "COMPANY_NAME_LEGAL := " | sed -e 's/COMPANY_NAME_LEGAL := //g')
|
||||
BRANDING_COMPANY_NAME_SHORT=$(cat ${TOPLEVEL_BRANDING} | grep -F "COMPANY_NAME_SHORT := " | sed -e 's/COMPANY_NAME_SHORT := //g')
|
||||
BRANDING_PRODUCT_BRAND=$(cat ${TOPLEVEL_BRANDING} | grep "^PRODUCT_BRAND := " | sed -e 's/PRODUCT_BRAND := //g')
|
||||
BRANDING_COMPANY_URL=www.$(cat ${TOPLEVEL_BRANDING} | grep -F "COMPANY_DOMAIN := " | sed -e 's/COMPANY_DOMAIN := //g')
|
||||
BRANDING_PRODUCT_VERSION_TEXT=$(cat ${TOPLEVEL_VERSIONS} | grep -F "PRODUCT_VERSION_TEXT := " | sed -e 's/PRODUCT_VERSION_TEXT := //g')
|
||||
BRANDING_PRODUCT_MAJOR_VERSION=$(cat ${TOPLEVEL_VERSIONS} | grep -F "PRODUCT_MAJOR_VERSION := " | sed -e 's/PRODUCT_MAJOR_VERSION := //g')
|
||||
BRANDING_PRODUCT_MINOR_VERSION=$(cat ${TOPLEVEL_VERSIONS} | grep -F "PRODUCT_MINOR_VERSION := " | sed -e 's/PRODUCT_MINOR_VERSION := //g')
|
||||
BRANDING_SERVER=${BRANDING_PRODUCT_BRAND}
|
||||
BRANDING_COMPANY_AND_PRODUCT=${BRANDING_PRODUCT_BRAND}
|
||||
BRANDING_BRAND_CONSOLE=$(cat ${TOPLEVEL_BRANDING} | grep -F "BRAND_CONSOLE := " | sed -e 's/BRAND_CONSOLE := //g')
|
||||
BRANDING_PV_TOOLS=${BRANDING_COMPANY_NAME_SHORT}\ VM\ Tools
|
||||
|
||||
# Check for the micro version override and use it if present otherwise use the one from branding
|
||||
if [ -n "${PRODUCT_MICRO_VERSION_OVERRIDE+x}" ]; then
|
||||
BRANDING_PRODUCT_MICRO_VERSION=${PRODUCT_MICRO_VERSION_OVERRIDE}
|
||||
echo Using override for micro product number of: ${BRANDING_PRODUCT_MICRO_VERSION}
|
||||
else
|
||||
BRANDING_PRODUCT_MICRO_VERSION=$(cat ${TOPLEVEL_VERSIONS} | grep -F "PRODUCT_MICRO_VERSION := " | sed -e 's/PRODUCT_MICRO_VERSION := //g')
|
||||
fi
|
||||
|
||||
BRANDING_XC_PRODUCT_VERSION=${BRANDING_PRODUCT_MAJOR_VERSION}.${BRANDING_PRODUCT_MINOR_VERSION}.${BRANDING_PRODUCT_MICRO_VERSION}
|
@ -1,292 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using CFUValidator.CommandLineOptions;
|
||||
using CFUValidator.OutputDecorators;
|
||||
using CFUValidator.Updates;
|
||||
using CFUValidator.Validators;
|
||||
using Moq;
|
||||
using XenAdmin;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Core;
|
||||
using XenAdminTests;
|
||||
using XenAPI;
|
||||
|
||||
namespace CFUValidator
|
||||
{
|
||||
public class CFUValidationException : Exception
|
||||
{
|
||||
public CFUValidationException(string message) : base(message){}
|
||||
}
|
||||
|
||||
public class CFUValidator
|
||||
{
|
||||
private readonly MockObjectManager mom = new MockObjectManager();
|
||||
private readonly XmlRetrieverFactory xmlFactory = new XmlRetrieverFactory();
|
||||
private const string id = "id";
|
||||
private string XmlLocation { get; set; }
|
||||
private string ServerVersion { get; set; }
|
||||
private OptionUsage UrlOrFile { get; set; }
|
||||
private List<string> InstalledHotfixes { get; set; }
|
||||
private bool CheckHotfixContents{ get; set; }
|
||||
|
||||
public CFUValidator(OptionUsage urlOrFile, string xmlLocation, string serverVersion,
|
||||
List<string> installedHotfixes, bool checkHotfixContents)
|
||||
{
|
||||
if(urlOrFile != OptionUsage.File && urlOrFile != OptionUsage.Url)
|
||||
throw new ArgumentException("urlOrFile option should be either File or Url");
|
||||
|
||||
mom.CreateNewConnection(id);
|
||||
ConnectionsManager.XenConnections.AddRange(mom.AllConnections);
|
||||
XmlLocation = xmlLocation;
|
||||
ServerVersion = serverVersion;
|
||||
InstalledHotfixes = installedHotfixes;
|
||||
UrlOrFile = urlOrFile;
|
||||
CheckHotfixContents = checkHotfixContents;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
List<XenServerPatch> xenServerPatches;
|
||||
List<XenServerVersion> xenServerVersions;
|
||||
List<XenCenterVersion> xenCenterVersions;
|
||||
|
||||
Status = "Getting check for updates XML from " + XmlLocation + "...";
|
||||
ReadCheckForUpdatesXML(out xenServerPatches, out xenServerVersions, out xenCenterVersions);
|
||||
|
||||
List<string> versionToCheck = GetVersionToCheck(xenServerVersions);
|
||||
|
||||
foreach (string ver in versionToCheck)
|
||||
{
|
||||
ServerVersion = ver;
|
||||
RunTestsForGivenServerVersion(xenServerVersions, xenServerPatches, xenCenterVersions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private List<string> GetVersionToCheck(List<XenServerVersion> xenServerVersions)
|
||||
{
|
||||
if(ServerVersion == CFUCommandLineOptionManager.AllVersions)
|
||||
return xenServerVersions.ConvertAll(i => i.Version.ToString()).Distinct().ToList();
|
||||
|
||||
return new List<string>{ServerVersion};
|
||||
}
|
||||
|
||||
private void RunTestsForGivenServerVersion(List<XenServerVersion> xenServerVersions,
|
||||
List<XenServerPatch> xenServerPatches,
|
||||
List<XenCenterVersion> xenCenterVersions)
|
||||
{
|
||||
CheckProvidedVersionNumber(xenServerVersions);
|
||||
|
||||
Status = String.Format("Generating server {0} mock-ups...", ServerVersion);
|
||||
SetupMocks(xenServerPatches, xenServerVersions);
|
||||
|
||||
Status = "Determining XenCenter update required...";
|
||||
var xcupdateAlerts = XenAdmin.Core.Updates.NewXenCenterUpdateAlerts(xenCenterVersions, new Version(ServerVersion));
|
||||
|
||||
Status = "Determining XenServer update required...";
|
||||
var updateAlerts = XenAdmin.Core.Updates.NewXenServerVersionAlerts(xenServerVersions).Where(alert => !alert.CanIgnore).ToList();
|
||||
|
||||
HfxEligibilityValidator hfxEligibilityValidator = new HfxEligibilityValidator(xenServerVersions);
|
||||
Status = "Running hotfix eligibility check...";
|
||||
RunHfxEligibilityValidator(hfxEligibilityValidator);
|
||||
|
||||
Status = "Determining patches required...";
|
||||
var patchAlerts = XenAdmin.Core.Updates.NewXenServerPatchAlerts(xenServerVersions, xenServerPatches).Where(alert => !alert.CanIgnore).ToList();
|
||||
|
||||
//Build patch checks list
|
||||
List<AlertFeatureValidator> validators = new List<AlertFeatureValidator>
|
||||
{
|
||||
new CorePatchDetailsValidator(patchAlerts),
|
||||
new PatchURLValidator(patchAlerts),
|
||||
new ZipContentsValidator(patchAlerts)
|
||||
};
|
||||
|
||||
Status = "Running patch check(s), this may take some time...";
|
||||
RunValidators(validators);
|
||||
|
||||
Status = "Generating summary...";
|
||||
GeneratePatchSummary(patchAlerts, validators, hfxEligibilityValidator, updateAlerts, xcupdateAlerts);
|
||||
}
|
||||
|
||||
private void CheckProvidedVersionNumber(List<XenServerVersion> xenServerVersions)
|
||||
{
|
||||
if (!xenServerVersions.Any(v => v.Version.ToString() == ServerVersion))
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("\nAvailable versions are:\n");
|
||||
xenServerVersions.ConvertAll(i=>i.Version.ToString()).Distinct().ToList().ForEach(v=>sb.AppendLine(v));
|
||||
throw new CFUValidationException("Could not find the version in the check for updates file: " + ServerVersion + sb);
|
||||
}
|
||||
}
|
||||
|
||||
public string Output { get; private set; }
|
||||
|
||||
#region Status event code
|
||||
public delegate void StatusChangedHandler(object sender, EventArgs e);
|
||||
|
||||
public event StatusChangedHandler StatusChanged;
|
||||
|
||||
protected virtual void OnStatusChanged()
|
||||
{
|
||||
if (StatusChanged != null)
|
||||
StatusChanged(Status, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private string status;
|
||||
private string Status
|
||||
{
|
||||
get { return status; }
|
||||
set
|
||||
{
|
||||
status = value;
|
||||
OnStatusChanged();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void RunValidators(List<AlertFeatureValidator> validators)
|
||||
{
|
||||
int count = 1;
|
||||
foreach (AlertFeatureValidator validator in validators)
|
||||
{
|
||||
if (validator is ZipContentsValidator && !CheckHotfixContents)
|
||||
continue;
|
||||
|
||||
Status = count++ + ". " + validator.Description + "...";
|
||||
|
||||
validator.StatusChanged += validator_StatusChanged;
|
||||
validator.Validate();
|
||||
validator.StatusChanged -= validator_StatusChanged;
|
||||
}
|
||||
Status = "Validator checks complete";
|
||||
}
|
||||
|
||||
private void RunHfxEligibilityValidator(HfxEligibilityValidator validator)
|
||||
{
|
||||
validator.Validate();
|
||||
Status = "Hotfix Eligibility Validator check complete";
|
||||
}
|
||||
|
||||
private void validator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
Status = sender as string;
|
||||
}
|
||||
|
||||
private void GeneratePatchSummary(List<XenServerPatchAlert> alerts, List<AlertFeatureValidator> validators, HfxEligibilityValidator hfxEligibilityValidator,
|
||||
List<XenServerVersionAlert> updateAlerts, List<XenCenterUpdateAlert> xcupdateAlerts)
|
||||
{
|
||||
OuputComponent oc = new OutputTextOuputComponent(XmlLocation, ServerVersion);
|
||||
XenCenterUpdateDecorator xcud = new XenCenterUpdateDecorator(oc, xcupdateAlerts);
|
||||
XenServerUpdateDecorator xsud = new XenServerUpdateDecorator(xcud, updateAlerts);
|
||||
HfxEligibilityValidatorDecorator hevd = new HfxEligibilityValidatorDecorator(xsud, hfxEligibilityValidator, "Hotfix eligibility check:");
|
||||
PatchAlertDecorator pad = new PatchAlertDecorator(hevd, alerts);
|
||||
AlertFeatureValidatorDecorator afdCoreFields = new AlertFeatureValidatorDecorator(pad,
|
||||
validators.First(v => v is CorePatchDetailsValidator),
|
||||
"Core fields in patch checks:");
|
||||
AlertFeatureValidatorDecorator afdPatchUrl = new AlertFeatureValidatorDecorator(afdCoreFields,
|
||||
validators.First(v => v is PatchURLValidator),
|
||||
"Required patch URL checks:");
|
||||
AlertFeatureValidatorDecorator afdZipContents = new AlertFeatureValidatorDecorator(afdPatchUrl,
|
||||
validators.First(v => v is ZipContentsValidator),
|
||||
"Required patch zip content checks:");
|
||||
|
||||
if (CheckHotfixContents)
|
||||
Output = afdZipContents.Generate().Insert(0, Output).ToString();
|
||||
else
|
||||
Output = afdPatchUrl.Generate().Insert(0, Output).ToString();
|
||||
|
||||
}
|
||||
|
||||
private void ReadCheckForUpdatesXML(out List<XenServerPatch> patches, out List<XenServerVersion> versions, out List<XenCenterVersion> xcVersions)
|
||||
{
|
||||
ICheckForUpdatesXMLSource checkForUpdates = xmlFactory.GetAction(UrlOrFile, XmlLocation);
|
||||
checkForUpdates.RunAsync();
|
||||
|
||||
ConsoleSpinner spinner = new ConsoleSpinner();
|
||||
while(!checkForUpdates.IsCompleted)
|
||||
{
|
||||
spinner.Turn(checkForUpdates.PercentComplete);
|
||||
}
|
||||
|
||||
if (checkForUpdates.ErrorRaised != null)
|
||||
throw checkForUpdates.ErrorRaised;
|
||||
|
||||
patches = checkForUpdates.XenServerPatches;
|
||||
versions = checkForUpdates.XenServerVersions;
|
||||
xcVersions = checkForUpdates.XenCenterVersions;
|
||||
}
|
||||
|
||||
private void SetupMocks(List<XenServerPatch> xenServerPatches, List<XenServerVersion> xenServerVersions)
|
||||
{
|
||||
Mock<Host> master = mom.NewXenObject<Host>(id);
|
||||
Mock<Pool> pool = mom.NewXenObject<Pool>(id);
|
||||
XenRef<Host> masterRef = new XenRef<Host>("ref");
|
||||
pool.Setup(p => p.master).Returns(masterRef);
|
||||
pool.Setup(p => p.other_config).Returns(new Dictionary<string, string>());
|
||||
mom.MockCacheFor(id).Setup(c => c.Resolve(It.IsAny<XenRef<Pool>>())).Returns(pool.Object);
|
||||
mom.MockConnectionFor(id).Setup(c => c.Resolve(masterRef)).Returns(master.Object);
|
||||
mom.MockConnectionFor(id).Setup(c => c.IsConnected).Returns(true);
|
||||
master.Setup(h => h.software_version).Returns(new Dictionary<string, string>());
|
||||
master.Setup(h => h.ProductVersion()).Returns(ServerVersion);
|
||||
master.Setup(h => h.AppliedPatches()).Returns(GenerateMockPoolPatches(xenServerPatches));
|
||||
|
||||
//Currently build number will be referenced first so if it's present hook it up
|
||||
string buildNumber = xenServerVersions.First(v => v.Version.ToString() == ServerVersion).BuildNumber;
|
||||
master.Setup(h=>h.BuildNumberRaw()).Returns(buildNumber);
|
||||
}
|
||||
|
||||
private List<Pool_patch> GenerateMockPoolPatches(List<XenServerPatch> xenServerPatches)
|
||||
{
|
||||
List<Pool_patch> patches = new List<Pool_patch>();
|
||||
|
||||
foreach (string installedHotfix in InstalledHotfixes)
|
||||
{
|
||||
string hotfix = installedHotfix;
|
||||
XenServerPatch match = xenServerPatches.Find(m => m.Name.Contains(hotfix));
|
||||
|
||||
if(match == null)
|
||||
throw new CFUValidationException("No patch could be found in the XML matching " + hotfix);
|
||||
|
||||
Mock<Pool_patch> pp = mom.NewXenObject<Pool_patch>(id);
|
||||
pp.Setup(p => p.uuid).Returns(match.Uuid);
|
||||
patches.Add(pp.Object);
|
||||
}
|
||||
|
||||
return patches;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{39308480-78C3-40B4-924D-06914F343ACD}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CFUValidator</RootNamespace>
|
||||
<AssemblyName>CFUValidator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.8.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.8.2\lib\net45\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CFUValidator.cs" />
|
||||
<Compile Include="CommandLineOptions\CommandLineArgument.cs" />
|
||||
<Compile Include="CommandLineOptions\CFUCommandLineOptionManager.cs" />
|
||||
<Compile Include="CommandLineOptions\CommandLineParser.cs" />
|
||||
<Compile Include="ConsoleSpinner.cs" />
|
||||
<Compile Include="OutputDecorators\AlertFeatureValidatorDecorator.cs" />
|
||||
<Compile Include="OutputDecorators\HfxEligibilityValidatorDecorator.cs" />
|
||||
<Compile Include="OutputDecorators\OuputComponent.cs" />
|
||||
<Compile Include="OutputDecorators\Decorator.cs" />
|
||||
<Compile Include="OutputDecorators\PatchAlertDecorator.cs" />
|
||||
<Compile Include="OutputDecorators\XenCenterUpdateDecorator.cs" />
|
||||
<Compile Include="OutputDecorators\XenServerUpdateDecorator.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Updates\AlternativeUrlDownloadUpdatesXmlSourceAction.cs" />
|
||||
<Compile Include="Updates\ReadFromFileUpdatesXmlSource.cs" />
|
||||
<Compile Include="Updates\ICheckForUpdatesXMLSource.cs" />
|
||||
<Compile Include="Updates\XmlRetrieverFactory.cs" />
|
||||
<Compile Include="Validators\AlertFeatureValidator.cs" />
|
||||
<Compile Include="Validators\HfxEligibilityValidator.cs" />
|
||||
<Compile Include="Validators\CorePatchDetailsValidator.cs" />
|
||||
<Compile Include="Validators\PatchURLValidator.cs" />
|
||||
<Compile Include="Validators\ZipContentsValidator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\XenAdminTests\XenAdminTests.csproj">
|
||||
<Project>{21B9482C-D255-40D5-ABA7-C8F00F99547C}</Project>
|
||||
<Name>XenAdminTests</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\XenAdmin\XenAdmin.csproj">
|
||||
<Project>{70BDA4BC-F062-4302-8ACD-A15D8BF31D65}</Project>
|
||||
<Name>XenAdmin</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\XenCenterLib\XenCenterLib.csproj">
|
||||
<Project>{9861DFA1-B41F-432D-A43F-226257DEBBB9}</Project>
|
||||
<Name>XenCenterLib</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\XenModel\XenModel.csproj">
|
||||
<Project>{B306FC59-4441-4A5F-9F54-D3F68D4EE38D}</Project>
|
||||
<Name>XenModel</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,131 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CFUValidator.CommandLineOptions
|
||||
{
|
||||
internal class CFUCommandLineOptionManager
|
||||
{
|
||||
private readonly List<CommandLineArgument> clas;
|
||||
public CFUCommandLineOptionManager(List<CommandLineArgument> clas)
|
||||
{
|
||||
this.clas = clas;
|
||||
}
|
||||
|
||||
//Not to be called from inside this class to keep IoC
|
||||
public static List<CommandLineArgument> EmptyArguments
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<CommandLineArgument>
|
||||
{
|
||||
new CommandLineArgument( OptionUsage.Help, 'h', "Display this help" ),
|
||||
new CommandLineArgument( OptionUsage.CheckZipContents, 'c', "Optionally check the zip contents of the hotfixes" ),
|
||||
new CommandLineArgument( OptionUsage.Url, 'u', "<URL to extract XML from> Cannot be used with -f flag"),
|
||||
new CommandLineArgument( OptionUsage.File, 'f', "<File name to extract XML from> Cannot be used with -u flag" ),
|
||||
new CommandLineArgument( OptionUsage.ServerVersion, 's', "<Server version to test> eg. 6.0.2" ),
|
||||
new CommandLineArgument( OptionUsage.Hotfix, 'p', "<List of patches/hotfixes that server has> eg. XS602E001 (space delimited)" )
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static string AllVersions = "999.999.999";
|
||||
|
||||
public string XmlLocation { get { return GetFileUsageCLA().Options.First(); } }
|
||||
|
||||
public bool CheckHotfixContents { get { return clas.First(c => c.Usage == OptionUsage.CheckZipContents).IsActiveOption; } }
|
||||
|
||||
private CommandLineArgument GetFileUsageCLA()
|
||||
{
|
||||
CommandLineArgument claForUrl = clas.First(c => c.Usage == OptionUsage.Url);
|
||||
CommandLineArgument claForFle = clas.First(c => c.Usage == OptionUsage.File);
|
||||
if (claForUrl.IsActiveOption && claForFle.IsActiveOption)
|
||||
throw new CFUValidationException(String.Format("Switches '-{0}' and '-{1}' cannot be used at the same time", claForFle.Switch, claForUrl.Switch));
|
||||
|
||||
if (!claForUrl.IsActiveOption && !claForFle.IsActiveOption)
|
||||
throw new CFUValidationException(String.Format("You must provide either option '-{0}' or '-{1}'", claForFle.Switch, claForUrl.Switch));
|
||||
|
||||
if (claForFle.IsActiveOption)
|
||||
return claForFle;
|
||||
|
||||
return claForUrl;
|
||||
}
|
||||
|
||||
public OptionUsage FileSource { get {return GetFileUsageCLA().Usage; } }
|
||||
|
||||
public string ServerVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
CommandLineArgument cla = clas.First(c => c.Usage == OptionUsage.ServerVersion);
|
||||
return !cla.IsActiveOption ? AllVersions : cla.Options.First();
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> InstalledHotfixes
|
||||
{
|
||||
get
|
||||
{
|
||||
CommandLineArgument cla = clas.First(c => c.Usage == OptionUsage.Hotfix);
|
||||
if (!cla.IsActiveOption)
|
||||
return new List<string>();
|
||||
return cla.Options;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsHelpRequired
|
||||
{
|
||||
get
|
||||
{
|
||||
return clas.First(c => c.Usage == OptionUsage.Help).IsActiveOption;
|
||||
}
|
||||
}
|
||||
|
||||
public string Help
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Execute the command with the following command line options\n\nOptions:\n");
|
||||
foreach (CommandLineArgument cla in clas.OrderBy(c => c.Switch))
|
||||
{
|
||||
sb.AppendLine(String.Format("-{0} {1}", cla.Switch, cla.Description));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CFUValidator.CommandLineOptions
|
||||
{
|
||||
public enum OptionUsage
|
||||
{
|
||||
Help,
|
||||
Url,
|
||||
File,
|
||||
Hotfix,
|
||||
ServerVersion,
|
||||
CheckZipContents
|
||||
}
|
||||
|
||||
public class CommandLineArgument
|
||||
{
|
||||
public CommandLineArgument(OptionUsage usage, char commandSwitch, string description)
|
||||
{
|
||||
Switch = commandSwitch;
|
||||
Description = description;
|
||||
Usage = usage;
|
||||
Options = null;
|
||||
IsActiveOption = false;
|
||||
}
|
||||
|
||||
public OptionUsage Usage { get; private set; }
|
||||
public char Switch { get; private set; }
|
||||
public List<string> Options { get; set; }
|
||||
public string Description { get; private set; }
|
||||
public bool IsActiveOption { get; set; }
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace CFUValidator.CommandLineOptions
|
||||
{
|
||||
public class CommandLineParser
|
||||
{
|
||||
private readonly string[] args;
|
||||
|
||||
public List<CommandLineArgument> ParsedArguments { get; private set; }
|
||||
|
||||
public CommandLineParser(string[] args, List<CommandLineArgument> argsToParse)
|
||||
{
|
||||
this.args = args;
|
||||
ParsedArguments = argsToParse;
|
||||
}
|
||||
|
||||
public void Parse()
|
||||
{
|
||||
string[] recastArgs = Regex.Split(string.Join(" ", args).Trim(), @"(?=[-])(?<=[ ])");
|
||||
foreach (string arg in recastArgs)
|
||||
{
|
||||
if(String.IsNullOrEmpty(arg))
|
||||
continue;
|
||||
|
||||
string optionSwitch = Regex.Match(arg, "[-]{1}[a-z]{1}").Value.Trim();
|
||||
char switchChar = Convert.ToChar(optionSwitch.Substring(1, 1));
|
||||
string[] splitArgs = arg.Replace(optionSwitch, "").Trim().Split(' ');
|
||||
|
||||
CommandLineArgument cla = ParsedArguments.FirstOrDefault(c => c.Switch == switchChar);
|
||||
if (cla != null)
|
||||
{
|
||||
cla.Options = splitArgs.Where(s=>!String.IsNullOrEmpty(s)).ToList();
|
||||
cla.IsActiveOption = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace CFUValidator
|
||||
{
|
||||
public class ConsoleSpinner
|
||||
{
|
||||
int counter;
|
||||
private const string working = "Working ";
|
||||
|
||||
public ConsoleSpinner()
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
public void Turn()
|
||||
{
|
||||
counter++;
|
||||
switch (counter % 4)
|
||||
{
|
||||
case 0: WriteAtOrigin(working + "/"); break;
|
||||
case 1: WriteAtOrigin(working + "-"); break;
|
||||
case 2: WriteAtOrigin(working + "\\"); break;
|
||||
case 3: WriteAtOrigin(working + "|"); break;
|
||||
}
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
public void Turn(double percentageComplete)
|
||||
{
|
||||
counter++;
|
||||
switch (counter % 4)
|
||||
{
|
||||
case 0: WriteAtOrigin(working + "/ (" + percentageComplete + "%)"); break;
|
||||
case 1: WriteAtOrigin(working + "- (" + percentageComplete + "%)"); break;
|
||||
case 2: WriteAtOrigin(working + "\\ (" + percentageComplete + "%)"); break;
|
||||
case 3: WriteAtOrigin(working + "| (" + percentageComplete + "%)"); break;
|
||||
}
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
private void WriteAtOrigin(string toWrite)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.SetCursorPosition(0, Console.CursorTop);
|
||||
Console.Write(toWrite);
|
||||
Console.SetCursorPosition(0, Console.CursorTop);
|
||||
}
|
||||
catch (SystemException){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using CFUValidator.Validators;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
class AlertFeatureValidatorDecorator : Decorator
|
||||
{
|
||||
private readonly string header;
|
||||
private readonly AlertFeatureValidator validator;
|
||||
public AlertFeatureValidatorDecorator(OuputComponent ouputComponent, AlertFeatureValidator validator, string header)
|
||||
{
|
||||
SetComponent(ouputComponent);
|
||||
this.validator = validator;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
StringBuilder sb = base.Generate();
|
||||
sb.AppendLine(header);
|
||||
if (validator.ErrorsFound)
|
||||
validator.Results.ForEach(v => sb.AppendLine(v));
|
||||
else
|
||||
sb.AppendLine("all OK");
|
||||
return sb.AppendLine(String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
abstract class Decorator : OuputComponent
|
||||
{
|
||||
private OuputComponent ouputComponent;
|
||||
public void SetComponent(OuputComponent ouputComponentToSet)
|
||||
{
|
||||
ouputComponent = ouputComponentToSet;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
if(ouputComponent != null)
|
||||
return ouputComponent.Generate();
|
||||
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using CFUValidator.Validators;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
class HfxEligibilityValidatorDecorator : Decorator
|
||||
{
|
||||
private readonly string header;
|
||||
private readonly HfxEligibilityValidator validator;
|
||||
public HfxEligibilityValidatorDecorator(OuputComponent ouputComponent, HfxEligibilityValidator validator, string header)
|
||||
{
|
||||
SetComponent(ouputComponent);
|
||||
this.validator = validator;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
StringBuilder sb = base.Generate();
|
||||
sb.AppendLine(header);
|
||||
if (validator.ErrorsFound)
|
||||
validator.Results.ForEach(v => sb.AppendLine(v));
|
||||
else
|
||||
sb.AppendLine("all OK");
|
||||
return sb.AppendLine(String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
public abstract class OuputComponent
|
||||
{
|
||||
public abstract StringBuilder Generate();
|
||||
}
|
||||
|
||||
public class OutputTextOuputComponent : OuputComponent
|
||||
{
|
||||
private readonly string location;
|
||||
private readonly string serverVersion;
|
||||
public OutputTextOuputComponent(string location, string serverVersion)
|
||||
{
|
||||
this.location = location;
|
||||
this.serverVersion = serverVersion;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
string header = String.Format("\nSummary for server version {0}, XML from {1}, generated on {2}\n\n", serverVersion,
|
||||
location, Date.ToLocalTime());
|
||||
return new StringBuilder(header);
|
||||
}
|
||||
|
||||
private DateTime Date
|
||||
{
|
||||
get { return DateTime.Now; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
|
||||
class PatchAlertDecorator : Decorator
|
||||
{
|
||||
private readonly List<XenServerPatchAlert> alerts;
|
||||
private const string header = "Patches required ({0}):";
|
||||
private const string zeroResults = "No patches required";
|
||||
private const string hotfixRegex = "XS[0-9]+E[A-Z]*[0-9]+";
|
||||
private const string unknown = "Name unknown (uuid={0})";
|
||||
|
||||
public PatchAlertDecorator(OuputComponent ouputComponent, List<XenServerPatchAlert> alerts)
|
||||
{
|
||||
SetComponent(ouputComponent);
|
||||
this.alerts = alerts;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
StringBuilder sb = base.Generate();
|
||||
sb.AppendLine(String.Format(header, alerts.Count));
|
||||
AddAlertSummary(sb);
|
||||
return sb.AppendLine(String.Empty);
|
||||
}
|
||||
|
||||
private void AddAlertSummary(StringBuilder sb)
|
||||
{
|
||||
if (alerts.Count == 0)
|
||||
sb.AppendLine(zeroResults);
|
||||
|
||||
foreach (XenServerPatchAlert alert in alerts.OrderBy(a => a.Patch.Name))
|
||||
{
|
||||
string patchName = Regex.Match(alert.Patch.Name, hotfixRegex).Value;
|
||||
string nameToReturn = String.IsNullOrEmpty(patchName) ? alert.Patch.Name.Trim() : patchName;
|
||||
|
||||
sb.AppendLine(!String.IsNullOrEmpty(nameToReturn)
|
||||
? nameToReturn
|
||||
: String.Format(unknown, alert.Patch.Uuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
class XenCenterUpdateDecorator: Decorator
|
||||
{
|
||||
private readonly List<XenCenterUpdateAlert> alerts;
|
||||
private const string header = "XenCenter updates required:";
|
||||
private const string updateNotFound = "XenCenter update could not be found";
|
||||
|
||||
public XenCenterUpdateDecorator(OuputComponent ouputComponent, List<XenCenterUpdateAlert> alerts)
|
||||
{
|
||||
SetComponent(ouputComponent);
|
||||
this.alerts = alerts;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
StringBuilder sb = base.Generate();
|
||||
sb.AppendLine(header);
|
||||
foreach (XenCenterUpdateAlert alert in alerts)
|
||||
{
|
||||
sb.AppendLine(alert == null ? updateNotFound : alert.NewVersion.VersionAndLang);
|
||||
}
|
||||
return sb.AppendLine(String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.OutputDecorators
|
||||
{
|
||||
class XenServerUpdateDecorator : Decorator
|
||||
{
|
||||
private readonly List<XenServerVersionAlert> alerts;
|
||||
private const string header = "XenServer updates required:";
|
||||
private const string updateNotFound = "XenServer update could not be found";
|
||||
|
||||
public XenServerUpdateDecorator(OuputComponent ouputComponent, List<XenServerVersionAlert> alerts)
|
||||
{
|
||||
SetComponent(ouputComponent);
|
||||
this.alerts = alerts;
|
||||
}
|
||||
|
||||
public override StringBuilder Generate()
|
||||
{
|
||||
StringBuilder sb = base.Generate();
|
||||
sb.AppendLine(header);
|
||||
foreach (XenServerVersionAlert alert in alerts)
|
||||
{
|
||||
sb.AppendLine(alert == null ? updateNotFound : alert.Version.Name);
|
||||
}
|
||||
return sb.AppendLine(String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using CFUValidator.CommandLineOptions;
|
||||
|
||||
namespace CFUValidator
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
CFUValidator cfuValidator = null;
|
||||
try
|
||||
{
|
||||
CommandLineParser parser = new CommandLineParser(args, CFUCommandLineOptionManager.EmptyArguments);
|
||||
parser.Parse();
|
||||
|
||||
CFUCommandLineOptionManager manager = new CFUCommandLineOptionManager(parser.ParsedArguments);
|
||||
|
||||
if(manager.IsHelpRequired || args.Length == 0)
|
||||
{
|
||||
Console.WriteLine(manager.Help);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
cfuValidator = new CFUValidator(manager.FileSource, manager.XmlLocation,
|
||||
manager.ServerVersion, manager.InstalledHotfixes,
|
||||
manager.CheckHotfixContents);
|
||||
cfuValidator.StatusChanged += cfuValidator_StatusChanged;
|
||||
cfuValidator.Run();
|
||||
Console.WriteLine(cfuValidator.Output);
|
||||
|
||||
}
|
||||
catch (CFUValidationException ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine("\n **** Unexpected exception occured ****: " + ex.Message);
|
||||
Console.WriteLine(ex.StackTrace);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (cfuValidator != null)
|
||||
cfuValidator.StatusChanged -= cfuValidator_StatusChanged;
|
||||
}
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
static void cfuValidator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine(sender as string);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CFUValidator")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("[Citrix]")]
|
||||
[assembly: AssemblyProduct("[XenCenter]")]
|
||||
[assembly: AssemblyCopyright("Copyright © [BRANDING_COMPANY_NAME_LEGAL]")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1fc53fff-32d6-4775-a913-203c3410d388")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,81 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using XenAdmin.Actions;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
namespace CFUValidator.Updates
|
||||
{
|
||||
class AlternativeUrlDownloadUpdatesXmlSourceAction : DownloadUpdatesXmlAction, ICheckForUpdatesXMLSource
|
||||
{
|
||||
private readonly string newLocation;
|
||||
|
||||
public AlternativeUrlDownloadUpdatesXmlSourceAction(string url)
|
||||
: base(true, true, true, "CFU", "1", url)
|
||||
{
|
||||
newLocation = url;
|
||||
ErrorRaised = null;
|
||||
}
|
||||
|
||||
protected override XmlDocument FetchCheckForUpdatesXml(string location)
|
||||
{
|
||||
XmlDocument xdoc;
|
||||
using (Stream xmlstream = GetXmlDoc())
|
||||
{
|
||||
xdoc = Helpers.LoadXmlDocument(xmlstream);
|
||||
}
|
||||
return xdoc;
|
||||
}
|
||||
|
||||
private Stream GetXmlDoc()
|
||||
{
|
||||
try
|
||||
{
|
||||
WebRequest wr = WebRequest.Create(newLocation);
|
||||
return wr.GetResponse().GetResponseStream();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
ErrorRaised = new CFUValidationException("Failed to wget the URL: " + newLocation);
|
||||
throw ErrorRaised;
|
||||
}
|
||||
}
|
||||
|
||||
public Exception ErrorRaised { get; private set; }
|
||||
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Core;
|
||||
|
||||
namespace CFUValidator.Updates
|
||||
{
|
||||
interface ICheckForUpdatesXMLSource
|
||||
{
|
||||
List<XenServerPatch> XenServerPatches { get; }
|
||||
List<XenServerVersion> XenServerVersions{ get; }
|
||||
List<XenCenterVersion> XenCenterVersions { get; }
|
||||
bool IsCompleted { get; }
|
||||
void RunAsync();
|
||||
int PercentComplete { get; }
|
||||
Exception ErrorRaised { get; }
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.Validators
|
||||
{
|
||||
abstract class AlertFeatureValidator
|
||||
{
|
||||
protected List<XenServerPatchAlert> alerts;
|
||||
|
||||
protected AlertFeatureValidator(List<XenServerPatchAlert> alerts)
|
||||
{
|
||||
this.alerts = alerts;
|
||||
Results = new List<string>();
|
||||
}
|
||||
|
||||
public abstract void Validate();
|
||||
public abstract string Description { get; }
|
||||
public List<string> Results { get; protected set; }
|
||||
public bool ErrorsFound { get { return Results.Count > 0; } }
|
||||
|
||||
public delegate void StatusChangedHandler(object sender, EventArgs e);
|
||||
|
||||
public event StatusChangedHandler StatusChanged;
|
||||
|
||||
protected virtual void OnStatusChanged()
|
||||
{
|
||||
if (StatusChanged != null)
|
||||
StatusChanged(Status, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private string status;
|
||||
protected string Status
|
||||
{
|
||||
get { return status; }
|
||||
set
|
||||
{
|
||||
status = value;
|
||||
OnStatusChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.Validators
|
||||
{
|
||||
class CorePatchDetailsValidator : AlertFeatureValidator
|
||||
{
|
||||
public CorePatchDetailsValidator(List<XenServerPatchAlert> alerts) : base(alerts){}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
foreach (XenServerPatchAlert alert in alerts)
|
||||
{
|
||||
VerifyPatchDetailsMissing(alert);
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyPatchDetailsMissing(XenServerPatchAlert alert)
|
||||
{
|
||||
if(string.IsNullOrEmpty(alert.Patch.Uuid))
|
||||
Results.Add("Missing patch uuid for patch: " + alert.Patch.Name);
|
||||
if(string.IsNullOrEmpty(alert.Patch.Name))
|
||||
Results.Add("Missing patch name for patch with UUID: " + alert.Patch.Uuid);
|
||||
if(string.IsNullOrEmpty(alert.Patch.PatchUrl))
|
||||
Results.Add("Missing patch patch-url for patch with UUID: " + alert.Patch.Uuid);
|
||||
if (string.IsNullOrEmpty(alert.Patch.Description))
|
||||
Results.Add("Missing patch description for patch with UUID: " + alert.Patch.Uuid);
|
||||
if (string.IsNullOrEmpty(alert.Patch.Url))
|
||||
Results.Add("Missing patch webpage url for patch with UUID: " + alert.Patch.Uuid);
|
||||
if (string.IsNullOrEmpty(alert.Patch.Guidance))
|
||||
Results.Add("Missing patch guidance for patch with UUID: " + alert.Patch.Uuid);
|
||||
if (string.IsNullOrEmpty(alert.Patch.TimeStamp.ToString()))
|
||||
Results.Add("Missing patch timestamp for patch with UUID: " + alert.Patch.Uuid);
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return "Verify core patch details"; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Core;
|
||||
|
||||
namespace CFUValidator.Validators
|
||||
{
|
||||
class HfxEligibilityValidator
|
||||
{
|
||||
private List<XenServerVersion> xsversions;
|
||||
public List<string> Results { get; set; }
|
||||
|
||||
public HfxEligibilityValidator(List<XenServerVersion> xsversions)
|
||||
{
|
||||
this.xsversions = xsversions;
|
||||
Results = new List<string>();
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
foreach (XenServerVersion version in xsversions)
|
||||
{
|
||||
DateSanityCheck(version);
|
||||
}
|
||||
}
|
||||
|
||||
private void DateSanityCheck(XenServerVersion version)
|
||||
{
|
||||
if (version.HotfixEligibility == hotfix_eligibility.none && version.EolDate == DateTime.MinValue)
|
||||
Results.Add("Missing or wrong eol-date field on: " + version.Name);
|
||||
if (version.HotfixEligibility == hotfix_eligibility.premium && version.HotfixEligibilityPremiumDate == DateTime.MinValue)
|
||||
Results.Add("Missing or wrong hotfix-eligibility-premium-date field on: " + version.Name);
|
||||
if (version.HotfixEligibility == hotfix_eligibility.cu && version.HotfixEligibilityNoneDate == DateTime.MinValue)
|
||||
Results.Add("Missing or wrong hotfix-eligibility-none-date field on: " + version.Name);
|
||||
if (version.HotfixEligibility == hotfix_eligibility.cu && version.HotfixEligibilityPremiumDate == DateTime.MinValue)
|
||||
Results.Add("Missing or wrong hotfix-eligibility-premium-date field on: " + version.Name);
|
||||
}
|
||||
|
||||
public bool ErrorsFound { get { return Results.Count > 0; } }
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Net;
|
||||
using XenAdmin.Alerts;
|
||||
|
||||
namespace CFUValidator.Validators
|
||||
{
|
||||
class PatchURLValidator : AlertFeatureValidator
|
||||
{
|
||||
private readonly BackgroundWorker workerThread;
|
||||
public PatchURLValidator(List<XenServerPatchAlert> alerts) : base(alerts)
|
||||
{
|
||||
workerThread = new BackgroundWorker();
|
||||
workerThread.DoWork += CheckAllPatchURLs;
|
||||
workerThread.RunWorkerCompleted += RunWorkerCompletedMethod;
|
||||
}
|
||||
|
||||
private bool isComplete;
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
isComplete = false;
|
||||
ConsoleSpinner spinner = new ConsoleSpinner();
|
||||
workerThread.RunWorkerAsync();
|
||||
|
||||
while(!isComplete)
|
||||
spinner.Turn();
|
||||
|
||||
}
|
||||
|
||||
private void RunWorkerCompletedMethod(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
isComplete = true;
|
||||
}
|
||||
|
||||
private void CheckAllPatchURLs(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
foreach (XenServerPatchAlert alert in alerts)
|
||||
{
|
||||
if(String.IsNullOrEmpty(alert.Patch.PatchUrl))
|
||||
{
|
||||
Results.Add(String.Format("Patch '{0}' URL is missing", alert.Patch.Name));
|
||||
continue;
|
||||
}
|
||||
|
||||
HttpWebResponse response = null;
|
||||
try
|
||||
{
|
||||
WebRequest request = WebRequest.Create(alert.Patch.PatchUrl);
|
||||
request.Method = "HEAD";
|
||||
response = (HttpWebResponse)request.GetResponse();
|
||||
if (response == null || response.StatusCode != HttpStatusCode.OK)
|
||||
Results.Add(String.Format("Patch '{0}' URL '{1}' is invalid", alert.Patch.Name, alert.Patch.PatchUrl));
|
||||
}
|
||||
catch(WebException ex)
|
||||
{
|
||||
Results.Add(String.Format("Patch '{0}' URL '{1}' failed: {2}", alert.Patch.Name, alert.Patch.PatchUrl, ex.Message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(response != null)
|
||||
response.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return "Checking the patch URLs return a suitable http response"; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using XenAdmin;
|
||||
using XenAdmin.Actions;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Core;
|
||||
using XenCenterLib.Archive;
|
||||
|
||||
namespace CFUValidator.Validators
|
||||
{
|
||||
class ZipContentsValidator : AlertFeatureValidator
|
||||
{
|
||||
public ZipContentsValidator(List<XenServerPatchAlert> alerts) : base(alerts){}
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
foreach (XenServerPatchAlert alert in alerts.OrderBy(a=>a.Patch.Name))
|
||||
{
|
||||
DownloadPatchFile(alert);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return "Downloading and checking the contents of the zip files in the patch"; }
|
||||
}
|
||||
|
||||
private string NewTempPath()
|
||||
{
|
||||
return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
}
|
||||
|
||||
private void DownloadPatchFile(XenServerPatchAlert patch)
|
||||
{
|
||||
if(string.IsNullOrEmpty(patch.Patch.PatchUrl))
|
||||
{
|
||||
Results.Add("Patch conatined no URL: " + patch.Patch.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
string tempFileName = NewTempPath();
|
||||
DownloadAndUnzipXenServerPatchAction action = new DownloadAndUnzipXenServerPatchAction(patch.Patch.Name,
|
||||
new Uri(patch.Patch.PatchUrl),
|
||||
tempFileName, false, BrandManager.ExtensionUpdate, InvisibleMessages.ISO_UPDATE);
|
||||
|
||||
try
|
||||
{
|
||||
Status = "Download and unzip patch " + patch.Patch.Name;
|
||||
|
||||
ConsoleSpinner spinner = new ConsoleSpinner();
|
||||
action.RunAsync();
|
||||
while(!action.IsCompleted)
|
||||
{
|
||||
spinner.Turn(action.PercentComplete);
|
||||
}
|
||||
|
||||
if(!action.Succeeded)
|
||||
Results.Add("Patch download and unzip unsuccessful: " + action.Exception.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Results.Add("Patch download error: " + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
|
@ -36,4 +36,4 @@ If you are unsure about something written here, ask on the XCP-ng forum https://
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
For a list of maintainers, please see MAINTAINERS file.
|
||||
For a list of maintainers, please see [MAINTAINERS](./MAINTAINERS.md) file.
|
39
CREDITS.md
Normal file
@ -0,0 +1,39 @@
|
||||
XenCenter Alumni
|
||||
================
|
||||
|
||||
* Aaron Robson
|
||||
* Adrian Jachacy
|
||||
* Barbara Li
|
||||
* Brian Donegan
|
||||
* Callum McIntyre
|
||||
* Carmen Agimof
|
||||
* Cheng Zhang
|
||||
* Chris Harding
|
||||
* Daniel Lamping
|
||||
* Darren Matthews
|
||||
* Deane Smith
|
||||
* Ewan Mellor
|
||||
* Frederico Mazzone
|
||||
* Gabor Apati-Nagy
|
||||
* Henry Hughes
|
||||
* Hugh Warrington
|
||||
* Hui Zhang
|
||||
* Javier Alvarez-Valle
|
||||
* Jisheng Xing
|
||||
* John Naab
|
||||
* Johnni Aguirre
|
||||
* Julie Allen
|
||||
* Katherine Shann
|
||||
* Kun Ma
|
||||
* Letsibogo Ramadi
|
||||
* Michael Zhao
|
||||
* Mihaela Stoica
|
||||
* Milind Padhye
|
||||
* Rabin Karki
|
||||
* Sarah Vallieres
|
||||
* Seren Corbett
|
||||
* Stephen Rice
|
||||
* Stephen Turner
|
||||
* Tom Wilkie
|
||||
* Usha Mandya
|
||||
* Victor Rodriguez
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="17.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@ -10,7 +10,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommandLib</RootNamespace>
|
||||
<AssemblyName>CommandLib</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
@ -42,10 +42,12 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\CommonAssemblyInfo.cs">
|
||||
<Link>Properties\CommonAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="export.cs" />
|
||||
<Compile Include="io.cs" />
|
||||
<Compile Include="tar.cs" />
|
||||
<Compile Include="thinCLIProtocol.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="XXHash.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,20 +29,15 @@
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CommandLib")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyDescription("[XenCenter] library")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("[Citrix]")]
|
||||
[assembly: AssemblyProduct("[XenCenter]")]
|
||||
[assembly: AssemblyCopyright("Copyright © [BRANDING_COMPANY_NAME_LEGAL]")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
@ -52,13 +46,3 @@ using System.Runtime.InteropServices;
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("afe05716-a4d5-415b-8263-9daa8639dc78")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("0000")]
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -37,199 +36,225 @@ using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using YYProject.XXHash;
|
||||
|
||||
/* Thrown if we fail to verify a block (ie sha1) checksum */
|
||||
public class BlockChecksumFailed : ApplicationException
|
||||
namespace CommandLib
|
||||
{
|
||||
private string block;
|
||||
private string recomputed;
|
||||
private string original;
|
||||
|
||||
public BlockChecksumFailed(string block, string recomputed, string original)
|
||||
/// <summary>
|
||||
/// Thrown if we fail to verify a block (ie sha1) checksum
|
||||
/// </summary>
|
||||
public class BlockChecksumFailed : ApplicationException
|
||||
{
|
||||
this.block = block;
|
||||
this.recomputed = recomputed;
|
||||
this.original = original;
|
||||
private string block;
|
||||
private string recomputed;
|
||||
private string original;
|
||||
|
||||
public BlockChecksumFailed(string block, string recomputed, string original)
|
||||
{
|
||||
this.block = block;
|
||||
this.recomputed = recomputed;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Failed to verify the block checksum: block = " + block + "; recomputed = " + recomputed + "; original = " + original;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public class Export
|
||||
{
|
||||
return "Failed to verify the block checksum: block = " + block + "; recomputed = " + recomputed + "; original = " + original;
|
||||
}
|
||||
}
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("csharpsquid",
|
||||
"S4790:Using weak hashing algorithms is security-sensitive",
|
||||
Justification = "Used only for checksum verification for backwards compatibility.")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("csharpsquid",
|
||||
"S2070:SHA-1 and Message-Digest hash algorithms should not be used in secure contexts",
|
||||
Justification = "Used only for checksum verification for backwards compatibility.")]
|
||||
private readonly SHA1 _sha1 = new SHA1CryptoServiceProvider();
|
||||
|
||||
private readonly XXHash64 _xxHash = new XXHash64();
|
||||
|
||||
private readonly bool _quiet;
|
||||
|
||||
public Export(bool quiet = false)
|
||||
{
|
||||
_quiet = quiet;
|
||||
}
|
||||
|
||||
private void Debug(string x)
|
||||
{
|
||||
if (_quiet)
|
||||
return;
|
||||
|
||||
public class Export
|
||||
{
|
||||
public static bool verbose_debugging = false;
|
||||
public static void debug(string x)
|
||||
{
|
||||
if (verbose_debugging)
|
||||
Console.WriteLine(x);
|
||||
}
|
||||
|
||||
private readonly SHA1 sha = new SHA1CryptoServiceProvider();
|
||||
private XXHash64 xxhash = new XXHash64();
|
||||
|
||||
private string checksum_sha1(byte[] data)
|
||||
{
|
||||
byte[] result = sha.ComputeHash(data);
|
||||
return hex(result).ToLower();
|
||||
}
|
||||
|
||||
private string hex(byte[] bytes)
|
||||
{
|
||||
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
char[] output = new char[bytes.Length * 2];
|
||||
|
||||
for(uint i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
uint b = (uint) bytes[i];
|
||||
output[i * 2] = chars[b >> 4];
|
||||
output[i * 2 + 1] = chars[b & 0x0F];
|
||||
}
|
||||
|
||||
return new string(output);
|
||||
}
|
||||
|
||||
private string checksum_xxhash(byte[] data)
|
||||
{
|
||||
xxhash.Initialize();
|
||||
return hex(xxhash.ComputeHash(data));
|
||||
}
|
||||
|
||||
private static Hashtable parse_checksum_table(string checksum_xml)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
|
||||
XmlDocument xmlDoc = new System.Xml.XmlDocument();
|
||||
xmlDoc.LoadXml(checksum_xml);
|
||||
XmlNodeList members = xmlDoc.GetElementsByTagName("member");
|
||||
string name;
|
||||
string value;
|
||||
foreach (XmlNode member in members)
|
||||
private string checksum_sha1(byte[] data)
|
||||
{
|
||||
name = ""; value = "";
|
||||
foreach (XmlNode child in member.ChildNodes)
|
||||
{
|
||||
XmlNode v = child.FirstChild;
|
||||
if (child.Name.Equals("name"))
|
||||
name = v.Value;
|
||||
if (child.Name.Equals("value"))
|
||||
value = v.Value;
|
||||
}
|
||||
debug(String.Format("adding {0} = {1}", name, value));
|
||||
table.Add(name, value);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private static void compare_tables(Hashtable recomputed, Hashtable original)
|
||||
{
|
||||
foreach (DictionaryEntry x in recomputed)
|
||||
{
|
||||
string ours = (string)x.Value;
|
||||
string theirs = (string)original[x.Key];
|
||||
if (!ours.Equals(theirs))
|
||||
{
|
||||
throw new BlockChecksumFailed((string)x.Key, ours, theirs);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(String.Format("{0} hash OK", (string)x.Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string string_of_byte_array(byte[] payload)
|
||||
{
|
||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
||||
char[] chars = new char[decoder.GetCharCount(payload, 0, (int)payload.Length)];
|
||||
decoder.GetChars(payload, 0, (int)payload.Length, chars, 0);
|
||||
return new string(chars);
|
||||
}
|
||||
|
||||
public delegate void verifyCallback(uint read);
|
||||
public delegate bool cancellingCallback();
|
||||
|
||||
/* 'input' is the source of the export data, if 'output' is not null then
|
||||
a perfect copy should be echoed there. */
|
||||
public void verify(Stream input, Stream output, cancellingCallback cancelling)
|
||||
{
|
||||
verify(input, output, cancelling, null);
|
||||
}
|
||||
|
||||
private Header nextHeader(Stream input, Stream output, verifyCallback callback)
|
||||
{ // Interperate the next bytes from the stream as a Tar header
|
||||
byte[] bytes = nextData(input, output, callback, Header.length);
|
||||
|
||||
if (Header.all_zeroes(bytes)) // Tar headers are 512-byte blocks in size
|
||||
{
|
||||
bytes = nextData(input, output, callback, Header.length);
|
||||
|
||||
if (Header.all_zeroes(bytes))
|
||||
{
|
||||
// Tars end with an End-Of-Archive marker, which is two consecutive 512-byte blocks of zero bytes
|
||||
throw new EndOfArchive();
|
||||
}
|
||||
byte[] result = _sha1.ComputeHash(data);
|
||||
return hex(result).ToLower();
|
||||
}
|
||||
|
||||
return new Header(bytes);
|
||||
}
|
||||
|
||||
private byte[] nextData(Stream input, Stream output, verifyCallback callback, uint size)
|
||||
{ // Returns the next given number of bytes from the input
|
||||
byte[] bytes = IO.unmarshal_n(input, size);
|
||||
callback?.Invoke(size);
|
||||
if (output != null) output.Write(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void verify(Stream input, Stream output, cancellingCallback cancelling, verifyCallback callback)
|
||||
{
|
||||
Hashtable recomputed_checksums = new Hashtable();
|
||||
Hashtable original_checksums = null;
|
||||
|
||||
try
|
||||
private string hex(byte[] bytes)
|
||||
{
|
||||
while (!cancelling())
|
||||
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
char[] output = new char[bytes.Length * 2];
|
||||
|
||||
for (uint i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
Header header_data = nextHeader(input, output, callback);
|
||||
debug(header_data.ToString());
|
||||
uint b = (uint)bytes[i];
|
||||
output[i * 2] = chars[b >> 4];
|
||||
output[i * 2 + 1] = chars[b & 0x0F];
|
||||
}
|
||||
|
||||
byte[] bytes_data = nextData(input, output, callback, header_data.file_size);
|
||||
return new string(output);
|
||||
}
|
||||
|
||||
if (header_data.file_name.Equals("ova.xml"))
|
||||
private string checksum_xxhash(byte[] data)
|
||||
{
|
||||
_xxHash.Initialize();
|
||||
return hex(_xxHash.ComputeHash(data));
|
||||
}
|
||||
|
||||
private Hashtable parse_checksum_table(string checksum_xml)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
|
||||
XmlDocument xmlDoc = new System.Xml.XmlDocument();
|
||||
xmlDoc.LoadXml(checksum_xml);
|
||||
XmlNodeList members = xmlDoc.GetElementsByTagName("member");
|
||||
string name;
|
||||
string value;
|
||||
foreach (XmlNode member in members)
|
||||
{
|
||||
name = "";
|
||||
value = "";
|
||||
foreach (XmlNode child in member.ChildNodes)
|
||||
{
|
||||
debug("Skipping ova.xml");
|
||||
XmlNode v = child.FirstChild;
|
||||
if (child.Name.Equals("name"))
|
||||
name = v.Value;
|
||||
if (child.Name.Equals("value"))
|
||||
value = v.Value;
|
||||
}
|
||||
else if (header_data.file_name.EndsWith("checksum.xml"))
|
||||
|
||||
Debug(String.Format("adding {0} = {1}", name, value));
|
||||
table.Add(name, value);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private void compare_tables(Hashtable recomputed, Hashtable original)
|
||||
{
|
||||
foreach (DictionaryEntry x in recomputed)
|
||||
{
|
||||
string ours = (string)x.Value;
|
||||
string theirs = (string)original[x.Key];
|
||||
if (!ours.Equals(theirs))
|
||||
{
|
||||
string xml = string_of_byte_array(bytes_data);
|
||||
original_checksums = parse_checksum_table(xml);
|
||||
throw new BlockChecksumFailed((string)x.Key, ours, theirs);
|
||||
}
|
||||
else
|
||||
{ // The file has no extension (must be a data file) so will have a .checksum or .xxhash file right after it
|
||||
Header header_checksum = nextHeader(input, output, callback);
|
||||
byte[] bytes_checksum = nextData(input, output, callback, header_checksum.file_size);
|
||||
string csum_compare = string_of_byte_array(bytes_checksum);
|
||||
|
||||
string csum = header_checksum.file_name.EndsWith(".xxhash") ? checksum_xxhash(bytes_data) : checksum_sha1(bytes_data);
|
||||
|
||||
if (!csum.Equals(csum_compare))
|
||||
throw new BlockChecksumFailed(header_data.file_name, csum, csum_compare);
|
||||
|
||||
debug(String.Format(" has checksum: {0}", csum));
|
||||
recomputed_checksums.Add(header_data.file_name, csum);
|
||||
|
||||
nextData(input, output, callback, header_checksum.paddingLength()); // Eat the padding for the checksum file
|
||||
{
|
||||
Debug(String.Format("{0} hash OK", (string)x.Key));
|
||||
}
|
||||
nextData(input, output, callback, header_data.paddingLength()); // Eat the padding for the data file
|
||||
}
|
||||
}
|
||||
catch (EndOfArchive)
|
||||
|
||||
private static string string_of_byte_array(byte[] payload)
|
||||
{
|
||||
debug("EOF");
|
||||
if (original_checksums != null)
|
||||
compare_tables(recomputed_checksums, original_checksums);
|
||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
||||
char[] chars = new char[decoder.GetCharCount(payload, 0, (int)payload.Length)];
|
||||
decoder.GetChars(payload, 0, (int)payload.Length, chars, 0);
|
||||
return new string(chars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 'input' is the source of the export data, if 'output' is not null then
|
||||
/// a perfect copy should be echoed there.
|
||||
/// </summary>
|
||||
public void verify(Stream input, Stream output, Func<bool> cancelling)
|
||||
{
|
||||
verify(input, output, cancelling, null);
|
||||
}
|
||||
|
||||
private Header nextHeader(Stream input, Stream output, Action<uint> callback)
|
||||
{
|
||||
// Interperate the next bytes from the stream as a Tar header
|
||||
byte[] bytes = nextData(input, output, callback, Header.length);
|
||||
|
||||
if (Header.all_zeroes(bytes)) // Tar headers are 512-byte blocks in size
|
||||
{
|
||||
bytes = nextData(input, output, callback, Header.length);
|
||||
|
||||
if (Header.all_zeroes(bytes))
|
||||
{
|
||||
// Tars end with an End-Of-Archive marker, which is two consecutive 512-byte blocks of zero bytes
|
||||
throw new EndOfArchive();
|
||||
}
|
||||
}
|
||||
|
||||
return new Header(bytes);
|
||||
}
|
||||
|
||||
private byte[] nextData(Stream input, Stream output, Action<uint> callback, uint size)
|
||||
{
|
||||
// Returns the next given number of bytes from the input
|
||||
byte[] bytes = IO.unmarshal_n(input, size);
|
||||
callback?.Invoke(size);
|
||||
if (output != null) output.Write(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void verify(Stream input, Stream output, Func<bool> cancelling, Action<uint> callback)
|
||||
{
|
||||
Hashtable recomputed_checksums = new Hashtable();
|
||||
Hashtable original_checksums = null;
|
||||
|
||||
try
|
||||
{
|
||||
while (!cancelling())
|
||||
{
|
||||
Header header_data = nextHeader(input, output, callback);
|
||||
Debug(header_data.ToString());
|
||||
|
||||
byte[] bytes_data = nextData(input, output, callback, header_data.file_size);
|
||||
|
||||
if (header_data.file_name.Equals("ova.xml"))
|
||||
{
|
||||
Debug("Skipping ova.xml");
|
||||
}
|
||||
else if (header_data.file_name.EndsWith("checksum.xml"))
|
||||
{
|
||||
string xml = string_of_byte_array(bytes_data);
|
||||
original_checksums = parse_checksum_table(xml);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The file has no extension (must be a data file) so will have a .checksum or .xxhash file right after it
|
||||
Header header_checksum = nextHeader(input, output, callback);
|
||||
byte[] bytes_checksum = nextData(input, output, callback, header_checksum.file_size);
|
||||
string csum_compare = string_of_byte_array(bytes_checksum);
|
||||
|
||||
string csum = header_checksum.file_name.EndsWith(".xxhash") ? checksum_xxhash(bytes_data) : checksum_sha1(bytes_data);
|
||||
|
||||
if (!csum.Equals(csum_compare))
|
||||
throw new BlockChecksumFailed(header_data.file_name, csum, csum_compare);
|
||||
|
||||
Debug(String.Format(" has checksum: {0}", csum));
|
||||
recomputed_checksums.Add(header_data.file_name, csum);
|
||||
|
||||
nextData(input, output, callback, header_checksum.paddingLength()); // Eat the padding for the checksum file
|
||||
}
|
||||
|
||||
nextData(input, output, callback, header_data.paddingLength()); // Eat the padding for the data file
|
||||
}
|
||||
}
|
||||
catch (EndOfArchive)
|
||||
{
|
||||
Debug("EOF");
|
||||
if (original_checksums != null)
|
||||
compare_tables(recomputed_checksums, original_checksums);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,40 +29,33 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
public class IO{
|
||||
namespace CommandLib
|
||||
{
|
||||
public class IO
|
||||
{
|
||||
private static void unmarshal_n_into(Stream stream, uint n, byte[] buffer)
|
||||
{
|
||||
int toread = (int)n;
|
||||
int offset = 0;
|
||||
while (toread > 0)
|
||||
{
|
||||
int nread = stream.Read(buffer, offset, toread);
|
||||
if (nread <= 0)
|
||||
throw new EndOfStreamException
|
||||
(String.Format("End of stream reached with {0} bytes left to read", toread));
|
||||
|
||||
public static void unmarshal_n_into(Stream stream, uint n, byte[] buffer){
|
||||
int toread = (int)n;
|
||||
int offset = 0;
|
||||
while (toread > 0){
|
||||
int nread = stream.Read(buffer, offset, toread);
|
||||
if (nread <= 0)
|
||||
throw new EndOfStreamException
|
||||
(String.Format("End of stream reached with {0} bytes left to read", toread));
|
||||
|
||||
offset += nread; toread -= nread;
|
||||
}
|
||||
}
|
||||
offset += nread;
|
||||
toread -= nread;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] unmarshal_n(Stream stream, uint n){
|
||||
byte[] buffer = new byte[n];
|
||||
unmarshal_n_into(stream, n, buffer);
|
||||
return buffer;
|
||||
public static byte[] unmarshal_n(Stream stream, uint n)
|
||||
{
|
||||
byte[] buffer = new byte[n];
|
||||
unmarshal_n_into(stream, n, buffer);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public static void skip(Stream stream, uint n){
|
||||
byte[] buffer = new byte[63356];
|
||||
while(n > 0){
|
||||
uint toread = (uint)buffer.Length;
|
||||
if (n < toread) toread = n;
|
||||
unmarshal_n_into(stream, toread, buffer);
|
||||
n -= toread;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,215 +1,232 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/* Thrown if we fail to verify a tar header checksum */
|
||||
public class HeaderChecksumFailed : ApplicationException {
|
||||
private uint expected;
|
||||
private uint received;
|
||||
public HeaderChecksumFailed(uint expected, uint received){
|
||||
this.expected = expected;
|
||||
this.received = received;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
string expected = Convert.ToString(this.expected);
|
||||
string received = Convert.ToString(this.received);
|
||||
|
||||
return "Failed to verify the tar header checksum: received = " + received + "; expected = " + expected;
|
||||
}
|
||||
}
|
||||
|
||||
/* Thrown when we find the end of archive marker (two zero blocks) */
|
||||
class EndOfArchive : ApplicationException {
|
||||
public EndOfArchive(){ }
|
||||
|
||||
public override string ToString(){
|
||||
return "End of tar archive";
|
||||
}
|
||||
}
|
||||
|
||||
public class Header{
|
||||
public string file_name;
|
||||
public int file_mode;
|
||||
public int user_id;
|
||||
public int group_id;
|
||||
public uint file_size;
|
||||
public uint mod_time;
|
||||
public bool link;
|
||||
public int link_name;
|
||||
|
||||
/* Length of a header block */
|
||||
public static uint length = 512;
|
||||
|
||||
/* http://en.wikipedia.org/w/index.php?title=Tar_%28file_format%29&oldid=83554041 */
|
||||
private static int file_name_off = 0;
|
||||
private static int file_name_len = 100;
|
||||
private static int file_mode_off = 100;
|
||||
private static int file_mode_len = 8;
|
||||
private static int user_id_off = 108;
|
||||
private static int user_id_len = 8;
|
||||
private static int group_id_off = 116;
|
||||
private static int group_id_len = 8;
|
||||
private static int file_size_off = 124;
|
||||
private static int file_size_len = 12;
|
||||
private static int mod_time_off = 136;
|
||||
private static int mod_time_len = 12;
|
||||
private static int chksum_off = 148;
|
||||
private static int chksum_len = 8;
|
||||
private static int link_off = 156;
|
||||
private static int link_len = 1;
|
||||
private static int link_name_off = 156;
|
||||
private static int link_name_len = 100;
|
||||
|
||||
/* True if a buffer contains all zeroes */
|
||||
public static bool all_zeroes(byte[] buffer){
|
||||
bool zeroes = true;
|
||||
for (int i = 0; i < buffer.Length && zeroes; i++) {
|
||||
if (buffer[i] != 0) zeroes = false;
|
||||
}
|
||||
return zeroes;
|
||||
}
|
||||
|
||||
/* Return a sub-array of bytes */
|
||||
private byte[] slice(byte[] input, int offset, int length){
|
||||
byte[] result = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = input[offset + i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Remove NULLs and spaces from the end of a string */
|
||||
private string trim_trailing_stuff(string x){
|
||||
char[] trimmed = { '\0', ' '};
|
||||
return x.TrimEnd(trimmed);
|
||||
}
|
||||
|
||||
/* Convert the byte array into a string (assume UTF8) */
|
||||
private string unmarshal_string(byte[] buffer){
|
||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
||||
char[] chars = new char[decoder.GetCharCount(buffer, 0, (int)buffer.Length)];
|
||||
decoder.GetChars(buffer, 0, (int)buffer.Length, chars, 0);
|
||||
return trim_trailing_stuff(new string(chars));
|
||||
}
|
||||
|
||||
/* Unmarshal an octal string into an int32 */
|
||||
private uint unmarshal_int32(byte[] buffer){
|
||||
string octal = "0" + unmarshal_string(buffer);
|
||||
return System.Convert.ToUInt32(octal, 8);
|
||||
}
|
||||
|
||||
/* Unmarshal an octal string into an int */
|
||||
private int unmarshal_int(byte[] buffer){
|
||||
string octal = "0" + unmarshal_string(buffer);
|
||||
return System.Convert.ToInt32(octal, 8);
|
||||
}
|
||||
|
||||
/* Recompute the (weak) header checksum */
|
||||
private uint compute_checksum(byte[] buffer){
|
||||
uint total = 0;
|
||||
for(int i = 0; i < buffer.Length; i++){
|
||||
/* treat the checksum digits as ' ' */
|
||||
if ((i >= chksum_off) && (i < (chksum_off + chksum_len))){
|
||||
total += 32; /* ' ' */
|
||||
} else {
|
||||
total += buffer[i];
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Compute the required length of padding data to follow the data payload */
|
||||
public uint paddingLength(){
|
||||
/* round up to the next whole number of blocks */
|
||||
uint next_block_length = (file_size + length - 1) / length * length;
|
||||
return next_block_length - file_size;
|
||||
}
|
||||
|
||||
/* pretty-print a header */
|
||||
public override string ToString(){
|
||||
return String.Format("{0}/{1} {2:000000000000} {3:000000000000} {4}",
|
||||
user_id, group_id, file_size, mod_time, file_name);
|
||||
}
|
||||
|
||||
/* Unmarshal a header from a buffer, throw an exception if the checksum doesn't validate */
|
||||
public Header(byte[] buffer){
|
||||
file_name = unmarshal_string(slice(buffer, file_name_off, file_name_len));
|
||||
file_mode = unmarshal_int(slice(buffer, file_mode_off, file_mode_len));
|
||||
user_id = unmarshal_int(slice(buffer, user_id_off, user_id_len));
|
||||
group_id = unmarshal_int(slice(buffer, group_id_off, group_id_len));
|
||||
file_size = unmarshal_int32(slice(buffer, file_size_off, file_size_len));
|
||||
mod_time = unmarshal_int32(slice(buffer, mod_time_off, mod_time_len));
|
||||
link = unmarshal_string(slice(buffer, link_off, link_len)) == "1";
|
||||
link_name = unmarshal_int(slice(buffer, link_name_off, link_name_len));
|
||||
|
||||
uint chksum = unmarshal_int32(slice(buffer, chksum_off, chksum_len));
|
||||
uint recomputed = compute_checksum(buffer);
|
||||
if (chksum != recomputed)
|
||||
throw new HeaderChecksumFailed(recomputed, chksum);
|
||||
|
||||
}
|
||||
|
||||
/* Read a tar header from a stream */
|
||||
public static Header fromStream(Stream input){
|
||||
byte[] one = IO.unmarshal_n(input, length);
|
||||
if (all_zeroes(one)){
|
||||
byte[] two = IO.unmarshal_n(input, length);
|
||||
if (all_zeroes(two))
|
||||
throw new EndOfArchive();
|
||||
return new Header(two);
|
||||
}
|
||||
return new Header(one);
|
||||
}
|
||||
}
|
||||
|
||||
public class Archive{
|
||||
|
||||
public static void list(Stream stream){
|
||||
try {
|
||||
while (true){
|
||||
Header x = Header.fromStream(stream);
|
||||
Console.WriteLine(x);
|
||||
IO.skip(stream, x.file_size);
|
||||
IO.skip(stream, x.paddingLength());
|
||||
}
|
||||
|
||||
}catch(EndOfArchive){
|
||||
Console.WriteLine("EOF");
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace CommandLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Thrown if we fail to verify a tar header checksum
|
||||
/// </summary>
|
||||
public class HeaderChecksumFailed : ApplicationException
|
||||
{
|
||||
private uint expected;
|
||||
private uint received;
|
||||
|
||||
public HeaderChecksumFailed(uint expected, uint received)
|
||||
{
|
||||
this.expected = expected;
|
||||
this.received = received;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string expected = Convert.ToString(this.expected);
|
||||
string received = Convert.ToString(this.received);
|
||||
|
||||
return "Failed to verify the tar header checksum: received = " + received + "; expected = " + expected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thrown when we find the end of archive marker (two zero blocks)
|
||||
/// </summary>
|
||||
class EndOfArchive : ApplicationException
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "End of tar archive";
|
||||
}
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
public string file_name;
|
||||
public int file_mode;
|
||||
public int user_id;
|
||||
public int group_id;
|
||||
public uint file_size;
|
||||
public uint mod_time;
|
||||
public bool link;
|
||||
public int link_name;
|
||||
|
||||
/* Length of a header block */
|
||||
public static uint length = 512;
|
||||
|
||||
/* http://en.wikipedia.org/w/index.php?title=Tar_%28file_format%29&oldid=83554041 */
|
||||
private static int file_name_off = 0;
|
||||
private static int file_name_len = 100;
|
||||
private static int file_mode_off = 100;
|
||||
private static int file_mode_len = 8;
|
||||
private static int user_id_off = 108;
|
||||
private static int user_id_len = 8;
|
||||
private static int group_id_off = 116;
|
||||
private static int group_id_len = 8;
|
||||
private static int file_size_off = 124;
|
||||
private static int file_size_len = 12;
|
||||
private static int mod_time_off = 136;
|
||||
private static int mod_time_len = 12;
|
||||
private static int chksum_off = 148;
|
||||
private static int chksum_len = 8;
|
||||
private static int link_off = 156;
|
||||
private static int link_len = 1;
|
||||
private static int link_name_off = 156;
|
||||
private static int link_name_len = 100;
|
||||
|
||||
/// <summary>
|
||||
/// True if a buffer contains all zeroes
|
||||
/// </summary>
|
||||
public static bool all_zeroes(byte[] buffer)
|
||||
{
|
||||
bool zeroes = true;
|
||||
for (int i = 0; i < buffer.Length && zeroes; i++)
|
||||
{
|
||||
if (buffer[i] != 0) zeroes = false;
|
||||
}
|
||||
|
||||
return zeroes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a sub-array of bytes
|
||||
/// </summary>
|
||||
private byte[] slice(byte[] input, int offset, int length)
|
||||
{
|
||||
byte[] result = new byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result[i] = input[offset + i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove NULLs and spaces from the end of a string
|
||||
/// </summary>
|
||||
private string trim_trailing_stuff(string x)
|
||||
{
|
||||
char[] trimmed = {'\0', ' '};
|
||||
return x.TrimEnd(trimmed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the byte array into a string (assume UTF8)
|
||||
/// </summary>
|
||||
private string unmarshal_string(byte[] buffer)
|
||||
{
|
||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
||||
char[] chars = new char[decoder.GetCharCount(buffer, 0, (int)buffer.Length)];
|
||||
decoder.GetChars(buffer, 0, (int)buffer.Length, chars, 0);
|
||||
return trim_trailing_stuff(new string(chars));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unmarshal an octal string into an int32
|
||||
/// </summary>
|
||||
private uint unmarshal_int32(byte[] buffer)
|
||||
{
|
||||
string octal = "0" + unmarshal_string(buffer);
|
||||
return System.Convert.ToUInt32(octal, 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unmarshal an octal string into an int
|
||||
/// </summary>
|
||||
private int unmarshal_int(byte[] buffer)
|
||||
{
|
||||
string octal = "0" + unmarshal_string(buffer);
|
||||
return System.Convert.ToInt32(octal, 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recompute the (weak) header checksum
|
||||
/// </summary>
|
||||
private uint compute_checksum(byte[] buffer)
|
||||
{
|
||||
uint total = 0;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
/* treat the checksum digits as ' ' */
|
||||
if ((i >= chksum_off) && (i < (chksum_off + chksum_len)))
|
||||
{
|
||||
total += 32; /* ' ' */
|
||||
}
|
||||
else
|
||||
{
|
||||
total += buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the required length of padding data to follow the data payload
|
||||
/// </summary>
|
||||
public uint paddingLength()
|
||||
{
|
||||
/* round up to the next whole number of blocks */
|
||||
uint next_block_length = (file_size + length - 1) / length * length;
|
||||
return next_block_length - file_size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// pretty-print a header
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}/{1} {2:000000000000} {3:000000000000} {4}",
|
||||
user_id, group_id, file_size, mod_time, file_name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unmarshal a header from a buffer, throw an exception if the checksum doesn't validate
|
||||
/// </summary>
|
||||
public Header(byte[] buffer)
|
||||
{
|
||||
file_name = unmarshal_string(slice(buffer, file_name_off, file_name_len));
|
||||
file_mode = unmarshal_int(slice(buffer, file_mode_off, file_mode_len));
|
||||
user_id = unmarshal_int(slice(buffer, user_id_off, user_id_len));
|
||||
group_id = unmarshal_int(slice(buffer, group_id_off, group_id_len));
|
||||
file_size = unmarshal_int32(slice(buffer, file_size_off, file_size_len));
|
||||
mod_time = unmarshal_int32(slice(buffer, mod_time_off, mod_time_len));
|
||||
link = unmarshal_string(slice(buffer, link_off, link_len)) == "1";
|
||||
link_name = unmarshal_int(slice(buffer, link_name_off, link_name_len));
|
||||
|
||||
uint chksum = unmarshal_int32(slice(buffer, chksum_off, chksum_len));
|
||||
uint recomputed = compute_checksum(buffer);
|
||||
if (chksum != recomputed)
|
||||
throw new HeaderChecksumFailed(recomputed, chksum);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,616 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Net.Security;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Authentication;
|
||||
|
||||
|
||||
|
||||
namespace CommandLib
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
public string hostname = ""; // no default hostname
|
||||
public string username = "root";
|
||||
public string password = "";
|
||||
public int port = 443;
|
||||
public int block_size = 65536;
|
||||
public bool nossl = false;
|
||||
public bool debug = false;
|
||||
}
|
||||
|
||||
public delegate void delegateGlobalError(String s);
|
||||
public delegate void delegateGlobalUsage();
|
||||
public delegate void delegateGlobalDebug(String s, thinCLIProtocol tCLIprotocol);
|
||||
public delegate void delegateConsoleWrite(String s);
|
||||
public delegate void delegateConsoleWriteLine(String s);
|
||||
public delegate string delegateConsoleReadLine();
|
||||
public delegate void delegateExit(int i);
|
||||
public delegate void delegateProgress(int i);
|
||||
|
||||
public class thinCLIProtocol
|
||||
{
|
||||
public delegateGlobalError dGlobalError;
|
||||
public delegateGlobalUsage dGlobalUsage;
|
||||
public delegateGlobalDebug dGlobalDebug;
|
||||
public delegateConsoleWrite dConsoleWrite;
|
||||
public delegateConsoleWriteLine dConsoleWriteLine;
|
||||
public delegateConsoleReadLine dConsoleReadLine;
|
||||
public delegateProgress dProgress;
|
||||
public delegateExit dExit;
|
||||
public Config conf;
|
||||
public string magic_string = "XenSource thin CLI protocol";
|
||||
public int major = 0;
|
||||
public int minor = 1;
|
||||
public bool dropOut;
|
||||
|
||||
public thinCLIProtocol(delegateGlobalError dGlobalError,
|
||||
delegateGlobalUsage dGlobalUsage,
|
||||
delegateGlobalDebug dGlobalDebug,
|
||||
delegateConsoleWrite dConsoleWrite,
|
||||
delegateConsoleWriteLine dConsoleWriteLine,
|
||||
delegateConsoleReadLine dConsoleReadLine,
|
||||
delegateExit dExit,
|
||||
delegateProgress dProgress,
|
||||
Config conf)
|
||||
{
|
||||
this.dGlobalError = dGlobalError;
|
||||
this.dGlobalUsage = dGlobalUsage;
|
||||
this.dGlobalDebug = dGlobalDebug;
|
||||
this.dConsoleWrite = dConsoleWrite;
|
||||
this.dConsoleWriteLine = dConsoleWriteLine;
|
||||
this.dConsoleReadLine = dConsoleReadLine;
|
||||
this.dExit = dExit;
|
||||
this.dProgress = dProgress;
|
||||
this.conf = conf;
|
||||
dropOut = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Transport{
|
||||
// The following method is invoked by the RemoteCertificateValidationDelegate.
|
||||
private static bool ValidateServerCertificate(
|
||||
object sender,
|
||||
X509Certificate certificate,
|
||||
X509Chain chain,
|
||||
SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
// Do allow this client to communicate with unauthenticated servers.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static Stream connect(thinCLIProtocol tCLIprotocol, String hostname, int port)
|
||||
{
|
||||
if (port != 443){
|
||||
TcpClient client = new TcpClient(hostname, port);
|
||||
Stream stream = client.GetStream();
|
||||
return stream;
|
||||
} else {
|
||||
TcpClient client = new TcpClient(hostname, port);
|
||||
// Create an SSL stream that will close the client's stream.
|
||||
SslStream sslStream = new SslStream(
|
||||
client.GetStream(),
|
||||
false,
|
||||
new RemoteCertificateValidationCallback(ValidateServerCertificate),
|
||||
null
|
||||
);
|
||||
try
|
||||
{
|
||||
sslStream.AuthenticateAsClient("", null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, true);
|
||||
}
|
||||
catch (AuthenticationException e){
|
||||
if (tCLIprotocol.conf.debug) throw e;
|
||||
tCLIprotocol.dGlobalError("Authentication failed - closing the connection.");
|
||||
client.Close();
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
if (tCLIprotocol.conf.debug) throw e;
|
||||
tCLIprotocol.dGlobalError("Exception during SSL auth - closing the connection.");
|
||||
client.Close();
|
||||
return null;
|
||||
}
|
||||
return sslStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HTTP{
|
||||
public static string readLine(Stream stream){
|
||||
StringBuilder messageData = new StringBuilder();
|
||||
do {
|
||||
int i = stream.ReadByte();
|
||||
if (i == -1)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
else
|
||||
{
|
||||
char b = (char)i;
|
||||
messageData.Append(b);
|
||||
if (b == '\n') break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return messageData.ToString();
|
||||
}
|
||||
|
||||
public static void writeLine(Stream stream, string line){
|
||||
byte[] message = Encoding.UTF8.GetBytes(string.Format("{0}\r\n", line));
|
||||
stream.Write(message, 0, message.Length);
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public static int getResultCode(string line){
|
||||
string[] bits = line.Split(new char[] {' '});
|
||||
if (bits.Length < 2) return 0;
|
||||
return Int32.Parse(bits[1]);
|
||||
}
|
||||
|
||||
public static Stream doRPC(String method, Uri uri, thinCLIProtocol tCLIprotocol, params string[] headers)
|
||||
{
|
||||
Stream http = Transport.connect(tCLIprotocol, uri.Host, uri.Port);
|
||||
String startLine = string.Format("{0} {1} HTTP/1.0", method, uri.PathAndQuery);
|
||||
writeLine(http, startLine);
|
||||
foreach (string h in headers)
|
||||
writeLine(http, h);
|
||||
writeLine(http, "");
|
||||
|
||||
String response = readLine(http);
|
||||
int code = getResultCode(response);
|
||||
switch (code)
|
||||
{
|
||||
case 200:
|
||||
break;
|
||||
case 302:
|
||||
string url = "";
|
||||
while (true)
|
||||
{
|
||||
response = readLine(http);
|
||||
if (response.StartsWith("Location: "))
|
||||
url = response.Substring(10);
|
||||
if (response.Equals("\r\n") || response.Equals("")) break;
|
||||
}
|
||||
Uri redirect = new Uri(url.Trim());
|
||||
tCLIprotocol.conf.hostname = redirect.Host;
|
||||
http.Close();
|
||||
return doRPC(method, redirect, tCLIprotocol, headers);
|
||||
default:
|
||||
tCLIprotocol.dGlobalError(string.Format("Received error code {0} from the server doing an HTTP {1}", code, method));
|
||||
http.Close();
|
||||
return null;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
response = readLine(http);
|
||||
if (response.Equals("\r\n") || response.Equals("")) break;
|
||||
}
|
||||
// Stream should be positioned after the headers
|
||||
return http;
|
||||
}
|
||||
}
|
||||
|
||||
public class Types{
|
||||
public static uint unmarshal_int32(Stream stream){
|
||||
uint a = (uint)stream.ReadByte();
|
||||
uint b = (uint)stream.ReadByte();
|
||||
uint c = (uint)stream.ReadByte();
|
||||
uint d = (uint)stream.ReadByte();
|
||||
//Console.WriteLine("a = " + a + " b = " + b + " c = " + c + " d = " + d);
|
||||
return (a << 0) | (b << 8) | (c << 16) | (d << 24);
|
||||
}
|
||||
public static void marshal_int32(Stream stream, uint x){
|
||||
uint mask = 0xff;
|
||||
stream.WriteByte((byte) ((x >> 0) & mask));
|
||||
stream.WriteByte((byte) ((x >> 8) & mask));
|
||||
stream.WriteByte((byte) ((x >> 16) & mask));
|
||||
stream.WriteByte((byte) ((x >> 24) & mask));
|
||||
}
|
||||
public static int unmarshal_int(Stream stream){
|
||||
return (int)unmarshal_int32(stream);
|
||||
}
|
||||
public static void marshal_int(Stream stream, int x){
|
||||
marshal_int32(stream, (uint)x);
|
||||
}
|
||||
public static byte[] unmarshal_n(Stream stream, uint n){
|
||||
byte[] buffer = new byte[n];
|
||||
int toread = (int)n;
|
||||
int offset = 0;
|
||||
while (toread > 0){
|
||||
int nread = stream.Read(buffer, offset, toread);
|
||||
offset= nread; toread -= nread;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
public static string unmarshal_string(Stream stream){
|
||||
uint length = unmarshal_int32(stream);
|
||||
byte[] buffer = unmarshal_n(stream, length);
|
||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
||||
char[] chars = new char[decoder.GetCharCount(buffer, 0, (int)length)];
|
||||
decoder.GetChars(buffer, 0, (int)length, chars, 0);
|
||||
return new string(chars);
|
||||
}
|
||||
public static void marshal_string(Stream stream, string x){
|
||||
marshal_int(stream, x.Length);
|
||||
char[] c = x.ToCharArray();
|
||||
Encoder encoder = Encoding.UTF8.GetEncoder();
|
||||
byte[] bytes = new byte[encoder.GetByteCount(c, 0, c.Length, true)];
|
||||
encoder.GetBytes(c, 0, c.Length, bytes, 0, true);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public class Messages
|
||||
{
|
||||
public enum tag
|
||||
{
|
||||
Print = 0, Load = 1, HttpGet = 12, HttpPut = 13, Prompt = 3, Exit = 4,
|
||||
Error = 14, OK = 5, Failed = 6, Chunk = 7, End = 8, Command = 9, Response = 10,
|
||||
Blob = 11, Debug = 15, PrintStderr = 16
|
||||
};
|
||||
public static tag unmarshal_tag(Stream stream)
|
||||
{
|
||||
int x = Types.unmarshal_int(stream);
|
||||
return (tag)x;
|
||||
}
|
||||
public static void marshal_tag(Stream stream, tag tag)
|
||||
{
|
||||
Types.marshal_int(stream, (int)tag);
|
||||
}
|
||||
public static void marshal_response(Stream stream, tag t)
|
||||
{
|
||||
Types.marshal_int(stream, 4 + 4);
|
||||
marshal_tag(stream, tag.Response);
|
||||
marshal_tag(stream, t);
|
||||
}
|
||||
public static void protocol_failure(string msg, tag t, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Protocol failure: Reading " + msg + ": unexpected tag: " + t);
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
|
||||
public static void load(Stream stream, string filename, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
FileInfo fi = new FileInfo(filename);
|
||||
// Immediately report our success in opening the file
|
||||
marshal_response(stream, tag.OK);
|
||||
|
||||
// The server doesn't like multiple chunks but this is fine for
|
||||
// Zurich/Geneva imports
|
||||
Types.marshal_int(stream, 4 + 4 + 4);
|
||||
marshal_tag(stream, tag.Blob);
|
||||
marshal_tag(stream, tag.Chunk);
|
||||
Types.marshal_int32(stream, (uint)fi.Length);
|
||||
|
||||
byte[] block = new byte[tCLIprotocol.conf.block_size];
|
||||
while (true)
|
||||
{
|
||||
int n = fs.Read(block, 0, block.Length);
|
||||
if (n == 0)
|
||||
{
|
||||
Types.marshal_int(stream, 4 + 4);
|
||||
marshal_tag(stream, tag.Blob);
|
||||
marshal_tag(stream, tag.End);
|
||||
break;
|
||||
}
|
||||
stream.Write(block, 0, n);
|
||||
tCLIprotocol.dProgress(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
marshal_response(stream, tag.Failed);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
marshal_response(stream, tag.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void http_put(Stream stream, string filename, Uri uri, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (Stream http = HTTP.doRPC("PUT", uri, tCLIprotocol,
|
||||
string.Format("Content-Length: {0}", fs.Length)))
|
||||
{
|
||||
if (http == null)
|
||||
{
|
||||
marshal_response(stream, tag.Failed);
|
||||
return;
|
||||
}
|
||||
byte[] block = new byte[tCLIprotocol.conf.block_size];
|
||||
while (true)
|
||||
{
|
||||
int n = fs.Read(block, 0, block.Length);
|
||||
if (n == 0) break;
|
||||
http.Write(block, 0, n);
|
||||
}
|
||||
marshal_response(stream, tag.OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("File not found");
|
||||
marshal_response(stream, tag.Failed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tCLIprotocol.dGlobalError(string.Format("Received exception: {0}", e.Message));
|
||||
marshal_response(stream, tag.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void http_get(Stream stream, string filename, Uri uri, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(filename))
|
||||
throw new Exception(string.Format("The file '{0}' already exists", filename));
|
||||
|
||||
using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
using (Stream http = HTTP.doRPC("GET", uri, tCLIprotocol))
|
||||
{
|
||||
if (http == null)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Server rejected request");
|
||||
marshal_response(stream, tag.Failed);
|
||||
return;
|
||||
}
|
||||
byte[] block = new byte[tCLIprotocol.conf.block_size];
|
||||
while (true)
|
||||
{
|
||||
int n = http.Read(block, 0, block.Length);
|
||||
if (n == 0) break;
|
||||
fs.Write(block, 0, n);
|
||||
}
|
||||
marshal_response(stream, tag.OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Received exception: " + e.Message);
|
||||
tCLIprotocol.dGlobalError("Unable to write output file: " + filename);
|
||||
marshal_response(stream, tag.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void version_handshake(Stream stream, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
/* Check for the initial magic string */
|
||||
byte[] magic = Types.unmarshal_n(stream, (uint)tCLIprotocol.magic_string.Length);
|
||||
for (int i = 0; i < tCLIprotocol.magic_string.Length; i++)
|
||||
{
|
||||
if (magic[i] != tCLIprotocol.magic_string[i])
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Failed to find a server on " + tCLIprotocol.conf.hostname + ":" + tCLIprotocol.conf.port);
|
||||
tCLIprotocol.dGlobalUsage();
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
}
|
||||
/* Read the remote version numbers */
|
||||
int remote_major = Types.unmarshal_int(stream);
|
||||
int remote_minor = Types.unmarshal_int(stream);
|
||||
tCLIprotocol.dGlobalDebug("Remote host has version " + remote_major + "." + remote_minor, tCLIprotocol);
|
||||
tCLIprotocol.dGlobalDebug("Client has version " + tCLIprotocol.major + "." + tCLIprotocol.minor, tCLIprotocol);
|
||||
if (tCLIprotocol.major != remote_major)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Protocol version mismatch talking to server on " + tCLIprotocol.conf.hostname + ":" + tCLIprotocol.conf.port);
|
||||
tCLIprotocol.dGlobalUsage();
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
/* Tell the server our version numbers */
|
||||
for (int i = 0; i < tCLIprotocol.magic_string.Length; i++)
|
||||
{
|
||||
stream.WriteByte((byte)tCLIprotocol.magic_string[i]);
|
||||
}
|
||||
Types.marshal_int(stream, tCLIprotocol.major);
|
||||
Types.marshal_int(stream, tCLIprotocol.minor);
|
||||
}
|
||||
|
||||
public static void performCommand(string Body, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
string body = Body;
|
||||
body += "username=" + tCLIprotocol.conf.username + "\n";
|
||||
body += "password=" + tCLIprotocol.conf.password + "\n";
|
||||
if (body.Length != 0)
|
||||
{
|
||||
body = body.Substring(0, body.Length - 1); // strip last "\n"
|
||||
}
|
||||
|
||||
string header = "POST /cli HTTP/1.0\r\n";
|
||||
string content_length = "content-length: " + Encoding.UTF8.GetBytes(body).Length + "\r\n";
|
||||
string tosend = header + content_length + "\r\n" + body;
|
||||
|
||||
try
|
||||
{
|
||||
Stream stream = Transport.connect(tCLIprotocol, tCLIprotocol.conf.hostname, tCLIprotocol.conf.port);
|
||||
if (stream == null)
|
||||
{
|
||||
// The SSL functions already tell us what happened
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
byte[] message = Encoding.UTF8.GetBytes(tosend);
|
||||
stream.Write(message, 0, message.Length);
|
||||
stream.Flush();
|
||||
Messages.version_handshake(stream, tCLIprotocol);
|
||||
interpreter(stream, tCLIprotocol);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
tCLIprotocol.dGlobalError("Connection to " + tCLIprotocol.conf.hostname + ":" + tCLIprotocol.conf.port + " refused.");
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (tCLIprotocol.conf.debug) throw e;
|
||||
tCLIprotocol.dGlobalError("Caught exception: " + e.Message);
|
||||
tCLIprotocol.dExit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void interpreter(Stream stream, thinCLIProtocol tCLIprotocol)
|
||||
{
|
||||
string filename = "";
|
||||
string path = "";
|
||||
string msg = "";
|
||||
while (!tCLIprotocol.dropOut)
|
||||
{
|
||||
Types.unmarshal_int32(stream); // total message length (unused here)
|
||||
Messages.tag t = Messages.unmarshal_tag(stream);
|
||||
switch (t)
|
||||
{
|
||||
case Messages.tag.Command:
|
||||
t = Messages.unmarshal_tag(stream);
|
||||
switch (t)
|
||||
{
|
||||
case Messages.tag.Print:
|
||||
msg = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dGlobalDebug("Read: Print: " + msg, tCLIprotocol);
|
||||
tCLIprotocol.dConsoleWriteLine(msg);
|
||||
break;
|
||||
case Messages.tag.PrintStderr:
|
||||
msg = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dGlobalDebug("Read: PrintStderr: " + msg, tCLIprotocol);
|
||||
tCLIprotocol.dConsoleWriteLine(msg);
|
||||
break;
|
||||
case Messages.tag.Debug:
|
||||
msg = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dGlobalDebug("Read: Debug: " + msg, tCLIprotocol);
|
||||
tCLIprotocol.dConsoleWriteLine(msg);
|
||||
break;
|
||||
case Messages.tag.Exit:
|
||||
int code = Types.unmarshal_int(stream);
|
||||
tCLIprotocol.dGlobalDebug("Read: Command Exit " + code, tCLIprotocol);
|
||||
tCLIprotocol.dExit(code);
|
||||
break;
|
||||
case Messages.tag.Error:
|
||||
tCLIprotocol.dGlobalDebug("Read: Command Error", tCLIprotocol);
|
||||
string err_code = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dConsoleWriteLine("Error code: " + err_code);
|
||||
tCLIprotocol.dConsoleWrite("Error params: ");
|
||||
int length = Types.unmarshal_int(stream);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
string param = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dConsoleWrite(param);
|
||||
if (i != (length - 1)) tCLIprotocol.dConsoleWrite(", ");
|
||||
}
|
||||
tCLIprotocol.dConsoleWriteLine("");
|
||||
break;
|
||||
case Messages.tag.Prompt:
|
||||
tCLIprotocol.dGlobalDebug("Read: Command Prompt", tCLIprotocol);
|
||||
string response = tCLIprotocol.dConsoleReadLine();
|
||||
tCLIprotocol.dConsoleWriteLine("Read "+response);
|
||||
/* NB, 4+4+4 here for the blob, chunk and string length, put in by the marshal_string
|
||||
function. A franken-marshal. */
|
||||
Types.marshal_int(stream, 4 + 4 + 4); // length
|
||||
Messages.marshal_tag(stream, Messages.tag.Blob);
|
||||
Messages.marshal_tag(stream, Messages.tag.Chunk);
|
||||
Types.marshal_string(stream, response);
|
||||
Types.marshal_int(stream, 4 + 4); // length
|
||||
Messages.marshal_tag(stream, Messages.tag.Blob);
|
||||
Messages.marshal_tag(stream, Messages.tag.End);
|
||||
break;
|
||||
case Messages.tag.Load:
|
||||
filename = Types.unmarshal_string(stream);
|
||||
tCLIprotocol.dGlobalDebug("Read: Load " + filename, tCLIprotocol);
|
||||
Messages.load(stream, filename, tCLIprotocol);
|
||||
break;
|
||||
case Messages.tag.HttpPut:
|
||||
filename = Types.unmarshal_string(stream);
|
||||
path = Types.unmarshal_string(stream);
|
||||
Uri uri = ParseUri(path, tCLIprotocol);
|
||||
tCLIprotocol.dGlobalDebug("Read: HttpPut " + filename + " -> " + uri, tCLIprotocol);
|
||||
Messages.http_put(stream, filename, uri, tCLIprotocol);
|
||||
break;
|
||||
case Messages.tag.HttpGet:
|
||||
filename = Types.unmarshal_string(stream);
|
||||
path = Types.unmarshal_string(stream);
|
||||
uri = ParseUri(path, tCLIprotocol);
|
||||
tCLIprotocol.dGlobalDebug("Read: HttpGet " + filename + " -> " + uri, tCLIprotocol);
|
||||
Messages.http_get(stream, filename, uri, tCLIprotocol);
|
||||
break;
|
||||
default:
|
||||
Messages.protocol_failure("Command", t, tCLIprotocol);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Messages.protocol_failure("Message", t, tCLIprotocol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Uri ParseUri(string path, thinCLIProtocol tcli)
|
||||
{
|
||||
// The server sometimes sends us a relative path (e.g. for VM import)
|
||||
// and sometimes an absolute URI (https://host/path). Construct the absolute URI
|
||||
// based on what we're given. The same hack exists in the server code...
|
||||
// See CA-10942.
|
||||
if (path.StartsWith("/"))
|
||||
{
|
||||
string[] bits = path.Split('?');
|
||||
UriBuilder uriBuilder = new UriBuilder();
|
||||
uriBuilder.Scheme = "https";
|
||||
uriBuilder.Host = tcli.conf.hostname;
|
||||
uriBuilder.Port = tcli.conf.port;
|
||||
uriBuilder.Path = bits[0];
|
||||
if (bits.Length > 1)
|
||||
uriBuilder.Query = bits[1];
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Uri(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,23 +29,17 @@
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace XenAdminTests.CodeTests
|
||||
{
|
||||
[TestFixture, Category(TestCategories.Unit)]
|
||||
public class XenModelReferencesTest
|
||||
{
|
||||
[Test]
|
||||
public void TestReferences()
|
||||
{
|
||||
Assembly a = Assembly.Load(new AssemblyName("XenModel"));
|
||||
AssemblyName[] an = a.GetReferencedAssemblies();
|
||||
[assembly: AssemblyCompany("[XenServerProduct]")]
|
||||
[assembly: AssemblyCopyright("Copyright © [Vendor Legal]")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyVersion("0.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("0000")]
|
||||
|
||||
foreach (AssemblyName name in an)
|
||||
{
|
||||
Assert.False(name.ToString().StartsWith("System.Windows"), "Assembly referenced: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* .NET Framework 4.8 docs: All components of the version must be integers greater
|
||||
* than or equal to 0. Metadata restricts the major, minor, build, and revision
|
||||
* components for an assembly to a maximum value of UInt16.MaxValue - 1.
|
||||
* If a component exceeds this value, a compilation error occurs.
|
||||
*/
|
66
Jenkinsfile
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
#!groovy
|
||||
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
def XENADMIN_BRANDING_TAG = 'v5.4'
|
||||
|
||||
@Library(['PacmanSharedLibrary', "xencenter-pipeline@v4.12"])
|
||||
import com.xenserver.pipeline.xencenter.*
|
||||
|
||||
properties([
|
||||
[
|
||||
$class : 'BuildDiscarderProperty',
|
||||
strategy: [
|
||||
$class: 'LogRotator',
|
||||
numToKeepStr: '10',
|
||||
artifactNumToKeepStr: '10'
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
def builder = null
|
||||
def globals = globals()
|
||||
|
||||
node(globals.buildNodeLabel) {
|
||||
try {
|
||||
builder = new Build(globals)
|
||||
builder.xenadminBrandingTag = XENADMIN_BRANDING_TAG
|
||||
|
||||
runPipeline(builder)
|
||||
currentBuild.result = 'SUCCESS'
|
||||
|
||||
} catch (Throwable ex) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw ex
|
||||
} finally {
|
||||
buildComplete(builder)
|
||||
}
|
||||
}
|
7
LICENSE
@ -1,4 +1,7 @@
|
||||
Copyright (c) 2020 XCP-ng Project
|
||||
|
||||
Copyright (c) Cloud Software Group, Inc.
|
||||
|
||||
Copyright (c) 2023 XCP-ng Project
|
||||
|
||||
The 2-Clause BSD License
|
||||
|
||||
@ -15,7 +18,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
|
||||
|
||||
Copyright for portions of XCP-ng Center are held by Citrix Systems, Inc.
|
||||
as part of Citrix® XenServer® and Citrix® XenCenter®:
|
||||
as part of Citrix® XenServer® and Citrix® XenCenter®:
|
||||
|
||||
Copyright (c) Citrix Systems, Inc.
|
||||
All rights reserved.
|
||||
|
@ -1,8 +0,0 @@
|
||||
List of maintainers
|
||||
===================
|
||||
|
||||
* Alexander Schulz (https://github.com/borzel)
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
For information on how to contribute to the project, please see CONTRIB file.
|
11
MAINTAINERS.md
Normal file
@ -0,0 +1,11 @@
|
||||
List of maintainers
|
||||
===================
|
||||
|
||||
* Konstantina Chremmou <konstantina.chremmou@cloud.com>
|
||||
* Chris Lancaster <chris.lancaster@cloud.com>
|
||||
* Danilo Del Busso <danilo.delbusso@cloud.com>
|
||||
* Joey Jiang <joey.jiang@cloud.com>
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
For information on how to contribute to the project, please see [CONTRIBUTING](./CONTRIBUTING.md) file.
|
@ -7,8 +7,8 @@ XCP-ng Center
|
||||
|
||||
This repository contains the source code for XCP-ng Center.
|
||||
|
||||
XCP-ng Center is a Windows-based management tool for XCP-ng and Citrix® XenServer® environments
|
||||
which enables users to manage and monitor XCP-ng and Citrix® XenServer® hosts and resource pools,
|
||||
XCP-ng Center is a Windows-based management tool for XCP-ng and Citrix® XenServer® environments
|
||||
which enables users to manage and monitor XCP-ng and Citrix® XenServer® hosts and resource pools,
|
||||
and to deploy, monitor, manage and migrate virtual machines.
|
||||
|
||||
XCP-ng Center is written mostly in C#.
|
||||
|
@ -14,18 +14,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xva_verify", "xva_verify\xv
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenCenterLib", "XenCenterLib\XenCenterLib.csproj", "{9861DFA1-B41F-432D-A43F-226257DEBBB9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenCenterVNC", "XenCenterVNC\XenCenterVNC.csproj", "{BD345C89-E8F4-4767-9BE0-1F0EAB7FA927}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenModel", "XenModel\XenModel.csproj", "{B306FC59-4441-4A5F-9F54-D3F68D4EE38D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenOvfApi", "XenOvfApi\XenOvfApi.csproj", "{2D78AC6C-B867-484A-A447-3C6FC8B8EAF7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenOvfTransport", "XenOvfTransport\XenOvfTransport.csproj", "{9F7E6285-5CBF-41B4-8CB9-AB06DFF90DC0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CFUValidator", "CFUValidator\CFUValidator.csproj", "{39308480-78C3-40B4-924D-06914F343ACD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XenServerHealthCheck", "XenServerHealthCheck\XenServerHealthCheck.csproj", "{DEB3208D-1153-407C-8C99-0D8899BE25A5}"
|
||||
EndProject
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "installer-xcp-ng", "installer-xcp-ng\installer-xcp-ng.wixproj", "{E0BDD733-D6EB-4EAF-B020-ED0F1154CF80}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xe", "xe\Xe.csproj", "{727E885D-14BE-40F0-9D0B-3853D44D3984}"
|
||||
|
117
XenAdmin/Actions/GUIActions/ConfigYumRepoAction.cs
Normal file
@ -0,0 +1,117 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
|
||||
namespace XenAdmin.Actions.GUIActions
|
||||
{
|
||||
internal class ConfigYumRepoAction : AsyncAction
|
||||
{
|
||||
private readonly RepoDescriptor _repoToEnable;
|
||||
private readonly Repository _introducedRepo;
|
||||
private readonly List<Repository> _oldEnabledRepos;
|
||||
private readonly Pool _pool;
|
||||
|
||||
public ConfigYumRepoAction(IXenConnection connection, RepoDescriptor repoDescriptor)
|
||||
: base(connection, string.Empty)
|
||||
{
|
||||
Title = Description = string.Format(Messages.YUM_REPO_ACTION_CONFIG_TITLE, connection.Name, repoDescriptor.FriendlyName);
|
||||
|
||||
_repoToEnable = repoDescriptor;
|
||||
|
||||
_introducedRepo = connection.Cache.Repositories.FirstOrDefault(r => _repoToEnable.MatchesRepository(r));
|
||||
|
||||
_pool = Helpers.GetPoolOfOne(Connection);
|
||||
|
||||
_oldEnabledRepos = (from XenRef<Repository> repoRef in _pool.repositories
|
||||
let repo = Connection.Resolve(repoRef)
|
||||
where !_repoToEnable.MatchesRepository(repo)
|
||||
select repo).ToList();
|
||||
|
||||
#region RBAC
|
||||
|
||||
if (_oldEnabledRepos.Count > 0)
|
||||
ApiMethodsToRoleCheck.Add("Pool.remove_repository");
|
||||
|
||||
if (_introducedRepo == null)
|
||||
ApiMethodsToRoleCheck.Add("Repository.introduce");
|
||||
|
||||
ApiMethodsToRoleCheck.Add("Pool.add_repository");
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
foreach (var repo in _oldEnabledRepos)
|
||||
{
|
||||
var repoName = RepoDescriptor.AllRepos.FirstOrDefault(r => r.MatchesRepository(repo))?.FriendlyName ?? string.Empty;
|
||||
Description = string.Format(Messages.YUM_REPO_ACTION_CONFIG_DESCRIPTION_DISABLE, repoName);
|
||||
Pool.remove_repository(Session, _pool.opaque_ref, repo.opaque_ref);
|
||||
}
|
||||
|
||||
XenRef<Repository> repoRef;
|
||||
|
||||
if (_introducedRepo == null)
|
||||
{
|
||||
var baseRepo = RepoDescriptor.BaseRepo;
|
||||
|
||||
if (!Connection.Cache.Repositories.Any(r => baseRepo.MatchesRepository(r)))
|
||||
{
|
||||
Description = string.Format(Messages.YUM_REPO_ACTION_CONFIG_DESCRIPTION_INTRODUCE, baseRepo.FriendlyName);
|
||||
|
||||
Repository.introduce(Session, baseRepo.Key, baseRepo.FriendlyName, baseRepo.BinUrl, baseRepo.SourceUrl, false, "");
|
||||
}
|
||||
|
||||
Description = string.Format(Messages.YUM_REPO_ACTION_CONFIG_DESCRIPTION_INTRODUCE, _repoToEnable.FriendlyName);
|
||||
|
||||
repoRef = Repository.introduce(Session, _repoToEnable.Key, _repoToEnable.FriendlyName,
|
||||
_repoToEnable.BinUrl, _repoToEnable.SourceUrl, true, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
repoRef = new XenRef<Repository>(_introducedRepo.opaque_ref);
|
||||
}
|
||||
|
||||
Description = string.Format(Messages.YUM_REPO_ACTION_CONFIG_DESCRIPTION_ENABLE, _repoToEnable.FriendlyName);
|
||||
|
||||
Pool.add_repository(Session, _pool.opaque_ref, repoRef);
|
||||
|
||||
//wait until the cache has been updated so that the config panel can show
|
||||
//the new value if the action was triggered by hitting the Apply button
|
||||
|
||||
Connection.WaitFor(() => _pool.repositories.Contains(repoRef), null);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
public class DeleteAllAlertsAction : AsyncAction
|
||||
{
|
||||
private readonly IEnumerable<Alert> Alerts;
|
||||
|
||||
/// <param name="connection">May be null; this is expected for client-side alerts.</param>
|
||||
/// <param name="alerts"></param>
|
||||
public DeleteAllAlertsAction(IXenConnection connection, IEnumerable<Alert> alerts)
|
||||
: base(connection,
|
||||
GetActionTitle(connection, alerts.Count()),
|
||||
Messages.ACTION_REMOVE_ALERTS_DESCRIPTION)
|
||||
{
|
||||
this.Alerts = alerts;
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
Pool = Helpers.GetPoolOfOne(connection);
|
||||
Host = Helpers.GetMaster(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetActionTitle(IXenConnection connection, int alertCount)
|
||||
{
|
||||
return connection == null
|
||||
? alertCount == 1
|
||||
? Messages.ACTION_REMOVE_ALERTS_ON_CLIENT_TITLE_ONE
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CLIENT_TITLE, alertCount)
|
||||
: alertCount == 1
|
||||
? string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CONNECTION_TITLE_ONE, Helpers.GetName(connection))
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CONNECTION_TITLE, alertCount, Helpers.GetName(connection));
|
||||
}
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
int i = 0;
|
||||
int max = Alerts.Count();
|
||||
Exception e = null;
|
||||
LogDescriptionChanges = false;
|
||||
List<Alert> toBeDismissed = new List<Alert>();
|
||||
|
||||
try
|
||||
{
|
||||
var myList = new List<Alert>(Alerts);
|
||||
foreach (Alert a in myList)
|
||||
{
|
||||
PercentComplete = (i * 100) / max;
|
||||
i++;
|
||||
Description = string.Format(Messages.ACTION_REMOVE_ALERTS_PROGRESS_DESCRIPTION, i, max);
|
||||
|
||||
Alert a1 = a;
|
||||
BestEffort(ref e, delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
if (a1 is XenServerPatchAlert || a1 is XenServerVersionAlert)
|
||||
{
|
||||
toBeDismissed.Add(a1);
|
||||
}
|
||||
else if(a1 is XenCenterUpdateAlert)
|
||||
{
|
||||
a1.Dismiss();
|
||||
}
|
||||
else
|
||||
{
|
||||
a1.DismissSingle(Session);
|
||||
}
|
||||
}
|
||||
catch (Failure exn)
|
||||
{
|
||||
if (exn.ErrorDescription[0] != Failure.HANDLE_INVALID)
|
||||
throw;
|
||||
//remove alert from XenCenterAlerts; this will trigger the CollectionChanged event, on which we update the alert count
|
||||
if (Alert.FindAlert(a1) != null)
|
||||
Alert.RemoveAlert(a1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Updates.DismissUpdates(toBeDismissed);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogDescriptionChanges = true;
|
||||
}
|
||||
|
||||
Description = max == 1 ? Messages.ACTION_REMOVE_ALERTS_DONE_ONE : string.Format(Messages.ACTION_REMOVE_ALERTS_DONE, max);
|
||||
}
|
||||
}
|
||||
}
|
132
XenAdmin/Actions/GUIActions/DismissAlertsAction.cs
Normal file
@ -0,0 +1,132 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
public class DismissAlertsAction : AsyncAction
|
||||
{
|
||||
private readonly List<Alert> _alerts;
|
||||
|
||||
public DismissAlertsAction(List<Alert> alerts, IXenConnection connection = null)
|
||||
: base(connection, GetActionTitle(connection, alerts.Count),
|
||||
Messages.ACTION_REMOVE_ALERTS_DESCRIPTION)
|
||||
{
|
||||
_alerts = alerts;
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
Pool = Helpers.GetPoolOfOne(connection);
|
||||
Host = Helpers.GetCoordinator(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetActionTitle(IXenConnection connection, int alertCount)
|
||||
{
|
||||
if (connection == null)
|
||||
return alertCount == 1
|
||||
? Messages.ACTION_REMOVE_ALERTS_ON_CLIENT_TITLE_ONE
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CLIENT_TITLE, alertCount);
|
||||
|
||||
return alertCount == 1
|
||||
? string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CONNECTION_TITLE_ONE, Helpers.GetName(connection))
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_ON_CONNECTION_TITLE, alertCount, Helpers.GetName(connection));
|
||||
}
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
LogDescriptionChanges = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (Connection != null && Helpers.XapiEqualOrGreater_22_19_0(Connection))
|
||||
{
|
||||
var msgRefs = new List<XenRef<Message>>();
|
||||
var msgAlerts = new List<MessageAlert>();
|
||||
var otherAlerts = new List<Alert>();
|
||||
|
||||
foreach (var a in _alerts)
|
||||
{
|
||||
if (a is MessageAlert ma)
|
||||
{
|
||||
msgAlerts.Add(ma);
|
||||
msgRefs.Add(new XenRef<Message>(ma.Message.opaque_ref));
|
||||
}
|
||||
else
|
||||
{
|
||||
otherAlerts.Add(a);
|
||||
}
|
||||
}
|
||||
|
||||
int midPoint = 0;
|
||||
if (_alerts.Count > 0)
|
||||
midPoint = 100 * msgAlerts.Count / _alerts.Count;
|
||||
|
||||
if (msgAlerts.Count > 0)
|
||||
{
|
||||
RelatedTask = Message.async_destroy_many(Session, msgRefs);
|
||||
PollToCompletion(0, midPoint);
|
||||
Alert.RemoveAlert(a => msgAlerts.Contains(a));
|
||||
}
|
||||
|
||||
for (var i = 0; i < otherAlerts.Count; i++)
|
||||
{
|
||||
_alerts[i].Dismiss();
|
||||
PercentComplete = midPoint + i * (100 - midPoint) / otherAlerts.Count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < _alerts.Count; i++)
|
||||
{
|
||||
Description = string.Format(Messages.ACTION_REMOVE_ALERTS_PROGRESS_DESCRIPTION, i, _alerts.Count);
|
||||
_alerts[i].Dismiss();
|
||||
PercentComplete = i * 100 / _alerts.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogDescriptionChanges = true;
|
||||
}
|
||||
|
||||
Description = _alerts.Count == 1
|
||||
? Messages.ACTION_REMOVE_ALERTS_DONE_ONE
|
||||
: string.Format(Messages.ACTION_REMOVE_ALERTS_DONE, _alerts.Count);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -521,7 +520,7 @@ namespace XenAdmin.Actions
|
||||
ParamLabelsStr += "LBL_HOSTNAME|";
|
||||
ParamValuesStr += Messages.NAME + "|";
|
||||
ParamLabelsStr += "LBL_POOLMASTER|";
|
||||
ParamValuesStr += Messages.POOL_MASTER + "|";
|
||||
ParamValuesStr += Messages.POOL_COORDINATOR + "|";
|
||||
ParamLabelsStr += "LBL_ADDRESS|";
|
||||
ParamValuesStr += Messages.ADDRESS + "|";
|
||||
ParamLabelsStr += "LBL_UUID|";
|
||||
@ -640,7 +639,7 @@ namespace XenAdmin.Actions
|
||||
|
||||
|
||||
HostInfo buf = new HostInfo(host.name_label, host.address, host.uuid, cpu_usage,
|
||||
host.IsMaster() ? Messages.YES : Messages.NO, network_usage, usage,
|
||||
host.IsCoordinator() ? Messages.YES : Messages.NO, network_usage, usage,
|
||||
Convert.ToString(host.Uptime()), srSizeString, host.Description());
|
||||
m_Hosts.Add(buf);
|
||||
PercentComplete = Convert.ToInt32((++itemIndex) * baseIndex / itemCount);
|
||||
@ -776,7 +775,7 @@ namespace XenAdmin.Actions
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
|
||||
if (!vm.is_a_real_vm())
|
||||
if (!vm.IsRealVm())
|
||||
{
|
||||
PercentComplete = Convert.ToInt32((++itemIndex) * baseIndex / itemCount);
|
||||
continue;
|
||||
@ -959,7 +958,7 @@ namespace XenAdmin.Actions
|
||||
|
||||
items.Add(Messages.NAME);
|
||||
items.Add(Messages.UUID);
|
||||
items.Add(Messages.POOL_MASTER);
|
||||
items.Add(Messages.POOL_COORDINATOR);
|
||||
items.Add(Messages.ADDRESS);
|
||||
items.Add(Messages.OVERVIEW_CPU_USAGE);
|
||||
items.Add(Messages.OVERVIEW_MEMORY_USAGE);
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -195,8 +194,8 @@ namespace XenAdmin.Actions
|
||||
List<Role> rolesAbleToCompleteAction;
|
||||
bool ableToCompleteAction = Role.CanPerform(methodsToCheck, xenConnection, out rolesAbleToCompleteAction);
|
||||
|
||||
log.DebugFormat("Roles able to complete action: {0}", Role.FriendlyCSVRoleList(rolesAbleToCompleteAction));
|
||||
log.DebugFormat("Subject {0} has roles: {1}", xenConnection.Session.UserLogName(), Role.FriendlyCSVRoleList(xenConnection.Session.Roles));
|
||||
log.DebugFormat("Roles able to complete action: {0}", Role.FriendlyCsvRoleList(rolesAbleToCompleteAction));
|
||||
log.DebugFormat("Subject {0} has roles: {1}", xenConnection.Session.UserLogName(), Role.FriendlyCsvRoleList(xenConnection.Session.Roles));
|
||||
|
||||
if (ableToCompleteAction)
|
||||
{
|
||||
@ -207,7 +206,7 @@ namespace XenAdmin.Actions
|
||||
// Can't run on this connection, bail out
|
||||
string desc = string.Format(FriendlyErrorNames.RBAC_PERMISSION_DENIED_FRIENDLY_CONNECTION,
|
||||
xenConnection.Session.FriendlyRoleDescription(),
|
||||
Role.FriendlyCSVRoleList(rolesAbleToCompleteAction),
|
||||
Role.FriendlyCsvRoleList(rolesAbleToCompleteAction),
|
||||
xenConnection.Name);
|
||||
throw new Exception(desc);
|
||||
}
|
||||
@ -227,11 +226,10 @@ namespace XenAdmin.Actions
|
||||
{
|
||||
Program.Invoke(Program.MainWindow, delegate
|
||||
{
|
||||
using (var d = new ThreeButtonDialog(
|
||||
new ThreeButtonDialog.Details(System.Drawing.SystemIcons.Warning, string.Format(Messages.FORCE_CLOSE_PLUGIN_PROMPT, _menuItemFeature.ToString())),
|
||||
"ProcessForceClosePrompt",
|
||||
using (var d = new WarningDialog(string.Format(Messages.FORCE_CLOSE_PLUGIN_PROMPT, _menuItemFeature.ToString()),
|
||||
new ThreeButtonDialog.TBDButton(Messages.FORCE_CLOSE, DialogResult.Yes),
|
||||
new ThreeButtonDialog.TBDButton(Messages.ALLOW_TO_CONTINUE, DialogResult.No)))
|
||||
new ThreeButtonDialog.TBDButton(Messages.ALLOW_TO_CONTINUE, DialogResult.No))
|
||||
{HelpNameSetter = "ProcessForceClosePrompt"})
|
||||
{
|
||||
if (d.ShowDialog(Program.MainWindow) == DialogResult.Yes && !_extAppProcess.HasExited)
|
||||
_extAppProcess.Kill();
|
||||
@ -247,40 +245,40 @@ namespace XenAdmin.Actions
|
||||
}
|
||||
|
||||
// Returns a set of params which relate to the object you have selected in the treeview
|
||||
private List<string> RetrieveParams(IXenObject obj)
|
||||
private IEnumerable<string> RetrieveParams(IXenObject obj)
|
||||
{
|
||||
IXenConnection connection = obj.Connection;
|
||||
Host master = connection != null ? Helpers.GetMaster(connection) : null; // get master asserts connection is not null
|
||||
string masterAddress = EmptyParameter;
|
||||
var connection = obj?.Connection;
|
||||
var coordinator = connection != null ? Helpers.GetCoordinator(connection) : null; // get coordinator asserts connection is not null
|
||||
var coordinatorAddress = EmptyParameter;
|
||||
|
||||
if (master != null)
|
||||
if (coordinator != null)
|
||||
{
|
||||
masterAddress = Helpers.GetUrl(master.Connection);
|
||||
WriteTrustedCertificates(master.Connection);
|
||||
coordinatorAddress = Helpers.GetUrl(coordinator.Connection);
|
||||
WriteTrustedCertificates(coordinator.Connection);
|
||||
}
|
||||
|
||||
string sessionRef = connection.Session != null ? connection.Session.opaque_ref : EmptyParameter;
|
||||
string objCls = obj != null ? obj.GetType().Name : EmptyParameter;
|
||||
string objUuid = obj != null && connection.Session != null ? Helpers.GetUuid(obj) : EmptyParameter;
|
||||
return new List<string>(new string[] { masterAddress, sessionRef, objCls, objUuid });
|
||||
var sessionRef = connection?.Session != null ? connection.Session.opaque_ref : EmptyParameter;
|
||||
var objCls = obj != null ? obj.GetType().Name : EmptyParameter;
|
||||
var objUuid = connection?.Session != null ? Helpers.GetUuid(obj) : EmptyParameter;
|
||||
return new List<string>(new string[] { coordinatorAddress, sessionRef, objCls, objUuid });
|
||||
}
|
||||
|
||||
// Returns a set of params which relate to the connection in general, with no obj information
|
||||
private List<string> RetrieveParams(IXenConnection connection)
|
||||
{
|
||||
Host master = connection != null ? Helpers.GetMaster(connection) : null; // get master asserts connection is not null
|
||||
string masterAddress = EmptyParameter;
|
||||
Host coordinator = connection != null ? Helpers.GetCoordinator(connection) : null; // get coordinator asserts connection is not null
|
||||
string coordinatorAddress = EmptyParameter;
|
||||
|
||||
if (master != null)
|
||||
if (coordinator != null)
|
||||
{
|
||||
masterAddress = Helpers.GetUrl(master.Connection);
|
||||
WriteTrustedCertificates(master.Connection);
|
||||
coordinatorAddress = Helpers.GetUrl(coordinator.Connection);
|
||||
WriteTrustedCertificates(coordinator.Connection);
|
||||
}
|
||||
|
||||
string sessionRef = connection.Session != null ? connection.Session.opaque_ref : EmptyParameter;
|
||||
string sessionRef = connection?.Session != null ? connection.Session.opaque_ref : EmptyParameter;
|
||||
string objCls = BlankParamter;
|
||||
string objUuid = BlankParamter;
|
||||
return new List<string>(new string[] { masterAddress, sessionRef, objCls, objUuid });
|
||||
return new List<string>(new string[] { coordinatorAddress, sessionRef, objCls, objUuid });
|
||||
}
|
||||
|
||||
private void WriteTrustedCertificates(IXenConnection connection)
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -31,7 +30,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAPI;
|
||||
using XenAdmin.Model;
|
||||
|
||||
@ -61,9 +59,9 @@ namespace XenAdmin.Actions
|
||||
|
||||
if (newFolder != xenObjectCopy.Path)
|
||||
{
|
||||
ApiMethodsToRoleCheck.Add(type + ".remove_from_other_config", Folders.FOLDER);
|
||||
ApiMethodsToRoleCheck.AddWithKey(type + ".remove_from_other_config", Folders.FOLDER);
|
||||
if (!String.IsNullOrEmpty(newFolder))
|
||||
ApiMethodsToRoleCheck.Add(type + ".add_to_other_config", Folders.FOLDER);
|
||||
ApiMethodsToRoleCheck.AddWithKey(type + ".add_to_other_config", Folders.FOLDER);
|
||||
// TODO: Full RBAC for folders
|
||||
}
|
||||
foreach (string tag in oldTags)
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -78,11 +77,11 @@ namespace XenAdmin.Actions.GUIActions
|
||||
private vm_operations vmOperation;
|
||||
|
||||
public MeddlingAction(Task task)
|
||||
: base(task.Name(), task.Description(), false, false)
|
||||
: base(task.Name(), task.Description(), false)
|
||||
{
|
||||
RelatedTask = new XenRef<Task>(task.opaque_ref);
|
||||
|
||||
Host = task.Connection.Resolve(task.resident_on) ?? Helpers.GetMaster(task.Connection);
|
||||
Host = task.Connection.Resolve(task.resident_on) ?? Helpers.GetCoordinator(task.Connection);
|
||||
|
||||
Started = (task.created + task.Connection.ServerTimeOffset).ToLocalTime();
|
||||
SetAppliesToData(task);
|
||||
@ -164,8 +163,8 @@ namespace XenAdmin.Actions.GUIActions
|
||||
else
|
||||
{
|
||||
// A non-aware client has created this task. We'll create a new action for this, and place it under
|
||||
// the task.resident_on host, or if that doesn't resolve, the pool master.
|
||||
Host host = task.Connection.Resolve(task.resident_on) ?? Helpers.GetMaster(task.Connection);
|
||||
// the task.resident_on host, or if that doesn't resolve, the pool coordinator.
|
||||
Host host = task.Connection.Resolve(task.resident_on) ?? Helpers.GetCoordinator(task.Connection);
|
||||
if (host != null)
|
||||
AppliesTo.Add(host.opaque_ref);
|
||||
}
|
||||
@ -228,7 +227,7 @@ namespace XenAdmin.Actions.GUIActions
|
||||
}
|
||||
else
|
||||
{
|
||||
host1 = task.Connection.Resolve(task.resident_on) ?? Helpers.GetMaster(task.Connection);
|
||||
host1 = task.Connection.Resolve(task.resident_on) ?? Helpers.GetCoordinator(task.Connection);
|
||||
}
|
||||
|
||||
List<string> names = new List<string>();
|
||||
@ -314,7 +313,7 @@ namespace XenAdmin.Actions.GUIActions
|
||||
/// </summary>
|
||||
public static bool IsTaskUnwanted(Task task)
|
||||
{
|
||||
return task.XenCenterUUID() == Program.XenCenterUUID ||
|
||||
return task.GetXenCenterUUID() == Program.XenCenterUUID ||
|
||||
task.Connection.Resolve(task.subtask_of) != null ||
|
||||
GetVmOperation(task) == vm_operations.unknown;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -29,7 +28,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using XenAPI;
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -29,9 +28,8 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAdmin.Alerts;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
@ -56,11 +54,11 @@ namespace XenAdmin.Actions
|
||||
|
||||
Dictionary<string, string> other_config = pool.other_config;
|
||||
|
||||
if (other_config.ContainsKey(Updates.IgnorePatchKey))
|
||||
other_config.Remove(Updates.IgnorePatchKey);
|
||||
if (other_config.ContainsKey(XenServerPatchAlert.IgnorePatchKey))
|
||||
other_config.Remove(XenServerPatchAlert.IgnorePatchKey);
|
||||
|
||||
if (other_config.ContainsKey(Updates.LAST_SEEN_SERVER_VERSION_KEY))
|
||||
other_config.Remove(Updates.LAST_SEEN_SERVER_VERSION_KEY);
|
||||
if (other_config.ContainsKey(XenServerVersionAlert.LAST_SEEN_SERVER_VERSION_KEY))
|
||||
other_config.Remove(XenServerVersionAlert.LAST_SEEN_SERVER_VERSION_KEY);
|
||||
|
||||
|
||||
XenAPI.Pool.set_other_config(Connection.Session, pool.opaque_ref, other_config);
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -29,121 +28,114 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using XenAdmin.Network;
|
||||
using XenAdmin.Controls.CustomDataGraph;
|
||||
using XenAPI;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Actions
|
||||
{
|
||||
public class SaveDataSourceStateAction : PureAsyncAction
|
||||
public class SaveDataSourceStateAction : AsyncAction
|
||||
{
|
||||
List<DataSourceItem> DataSourceItems;
|
||||
List<DesignedGraph> Graphs;
|
||||
IXenObject XenObject;
|
||||
|
||||
private Pool GetPool()
|
||||
{
|
||||
return Helpers.GetPoolOfOne(Connection);
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetGuiConfig()
|
||||
{
|
||||
Pool pool = GetPool();
|
||||
return pool != null ? Helpers.GetGuiConfig(pool) : null;
|
||||
}
|
||||
private readonly List<DataSourceItem> _dataSourceItems;
|
||||
private readonly List<DesignedGraph> _graphs;
|
||||
private readonly IXenObject _xenObject;
|
||||
|
||||
public SaveDataSourceStateAction(IXenConnection connection, IXenObject xmo, List<DataSourceItem> items, List<DesignedGraph> graphs)
|
||||
: base(connection, Messages.ACTION_SAVE_DATASOURCES, Messages.ACTION_SAVING_DATASOURCES, true)
|
||||
{
|
||||
DataSourceItems = items;
|
||||
XenObject = xmo;
|
||||
Graphs = graphs;
|
||||
_dataSourceItems = items;
|
||||
_xenObject = xmo;
|
||||
_graphs = graphs;
|
||||
|
||||
if (xmo is Host)
|
||||
ApiMethodsToRoleCheck.AddRange("host.record_data_source", "host.forget_data_source_archives");
|
||||
else if (xmo is VM)
|
||||
ApiMethodsToRoleCheck.AddRange("VM.record_data_source", "VM.forget_data_source_archives");
|
||||
|
||||
ApiMethodsToRoleCheck.Add("pool.set_gui_config");
|
||||
}
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
Dictionary<string, string> gui_config = GetGuiConfig();
|
||||
Pool pool = Helpers.GetPoolOfOne(Connection);
|
||||
var guiConfig = pool?.gui_config;
|
||||
|
||||
if (DataSourceItems != null)
|
||||
if (_dataSourceItems != null)
|
||||
{
|
||||
foreach (DataSourceItem ds in DataSourceItems)
|
||||
foreach (DataSourceItem ds in _dataSourceItems)
|
||||
{
|
||||
if (ds.DataSource.enabled != ds.Enabled)
|
||||
{
|
||||
Host host = XenObject as Host;
|
||||
VM vm = XenObject as VM;
|
||||
if (host != null)
|
||||
if (_xenObject is Host host)
|
||||
{
|
||||
if (ds.Enabled)
|
||||
XenAPI.Host.record_data_source(Session, host.opaque_ref, ds.DataSource.name_label);
|
||||
Host.record_data_source(Session, host.opaque_ref, ds.DataSource.name_label);
|
||||
else
|
||||
XenAPI.Host.forget_data_source_archives(Session, host.opaque_ref, ds.DataSource.name_label);
|
||||
Host.forget_data_source_archives(Session, host.opaque_ref, ds.DataSource.name_label);
|
||||
}
|
||||
else if (vm != null)
|
||||
else if (_xenObject is VM vm)
|
||||
{
|
||||
if (ds.Enabled)
|
||||
XenAPI.VM.record_data_source(Session, vm.opaque_ref, ds.DataSource.name_label);
|
||||
VM.record_data_source(Session, vm.opaque_ref, ds.DataSource.name_label);
|
||||
else
|
||||
XenAPI.VM.forget_data_source_archives(Session, vm.opaque_ref, ds.DataSource.name_label);
|
||||
VM.forget_data_source_archives(Session, vm.opaque_ref, ds.DataSource.name_label);
|
||||
}
|
||||
}
|
||||
|
||||
if (ds.ColorChanged)
|
||||
if (ds.ColorChanged && guiConfig != null)
|
||||
{
|
||||
if (gui_config != null)
|
||||
{
|
||||
string key = Palette.GetColorKey(ds.DataSource.name_label, XenObject);
|
||||
string value = ds.Color.ToArgb().ToString();
|
||||
string key = Palette.GetColorKey(ds.DataSource.name_label, _xenObject);
|
||||
string value = ds.Color.ToArgb().ToString();
|
||||
|
||||
if (!gui_config.ContainsKey(key))
|
||||
gui_config.Add(key, value);
|
||||
else
|
||||
gui_config[key] = value;
|
||||
}
|
||||
if (!guiConfig.ContainsKey(key))
|
||||
guiConfig.Add(key, value);
|
||||
else
|
||||
guiConfig[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, string> new_gui_config = new Dictionary<string, string>();
|
||||
string uuid = Helpers.GetUuid(XenObject);
|
||||
var newGuiConfig = new Dictionary<string, string>();
|
||||
string uuid = Helpers.GetUuid(_xenObject);
|
||||
|
||||
// build new gui config dictionary:
|
||||
// add keys not related to current XenObject
|
||||
if (gui_config != null)
|
||||
if (guiConfig != null)
|
||||
{
|
||||
foreach (string key in gui_config.Keys)
|
||||
foreach (string key in guiConfig.Keys)
|
||||
{
|
||||
bool isMatch = (Palette.LayoutKey.IsMatch(key) || Palette.GraphNameKey.IsMatch(key));
|
||||
bool isMatch = Palette.LayoutKey.IsMatch(key) || Palette.GraphNameKey.IsMatch(key);
|
||||
if (isMatch && key.Contains(uuid))
|
||||
continue;
|
||||
new_gui_config.Add(key, gui_config[key]);
|
||||
newGuiConfig.Add(key, guiConfig[key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Graphs != null)
|
||||
if (_graphs != null)
|
||||
{
|
||||
// add current XenObject keys
|
||||
for (int i = 0; i < Graphs.Count; i++)
|
||||
for (int i = 0; i < _graphs.Count; i++)
|
||||
{
|
||||
string key = Palette.GetLayoutKey(i, XenObject);
|
||||
string value = Graphs[i].ToString();
|
||||
string key = Palette.GetLayoutKey(i, _xenObject);
|
||||
string value = _graphs[i].ToString();
|
||||
|
||||
// 'key' should not exist in the new gui config dictionary
|
||||
new_gui_config.Add(key, value);
|
||||
newGuiConfig.Add(key, value);
|
||||
|
||||
key = Palette.GetGraphNameKey(i, XenObject);
|
||||
value = Graphs[i].DisplayName;
|
||||
if (value != String.Empty)
|
||||
key = Palette.GetGraphNameKey(i, _xenObject);
|
||||
value = _graphs[i].DisplayName;
|
||||
if (value != string.Empty)
|
||||
{
|
||||
new_gui_config.Add(key, value);
|
||||
newGuiConfig.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XenAPI.Pool.set_gui_config(Session, GetPool().opaque_ref, new_gui_config);
|
||||
if (pool != null)
|
||||
Pool.set_gui_config(Session, pool.opaque_ref, newGuiConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,8 +29,6 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAdmin.XenSearch;
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,10 +29,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Reporting.WinForms;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Actions.Wlb
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -31,18 +30,14 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using XenAdmin.Commands;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Wlb;
|
||||
using XenAdmin.Dialogs;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
using System.Drawing;
|
||||
using XenAdmin.Actions.VMActions;
|
||||
|
||||
using XenAdmin.Actions.HostActions;
|
||||
using XenAdmin.Actions.VMActions;
|
||||
|
||||
namespace XenAdmin.Actions.Wlb
|
||||
{
|
||||
@ -58,13 +53,8 @@ namespace XenAdmin.Actions.Wlb
|
||||
public WlbOptimizePoolAction(Pool pool, Dictionary<VM, WlbOptimizationRecommendation> vmOptLst, string optId)
|
||||
: base(pool.Connection, string.Format(Messages.WLB_OPTIMIZING_POOL, Helpers.GetName(pool).Ellipsise(50)))
|
||||
{
|
||||
if (pool == null)
|
||||
throw new ArgumentNullException("pool");
|
||||
if (vmOptLst == null)
|
||||
throw new ArgumentNullException("vmOptLst");
|
||||
|
||||
this.Pool = pool;
|
||||
this.vmOptList = vmOptLst;
|
||||
Pool = pool;
|
||||
vmOptList = vmOptLst ?? throw new ArgumentNullException("vmOptLst");
|
||||
this.optId = optId;
|
||||
|
||||
#region RBAC Dependencies
|
||||
@ -244,11 +234,8 @@ namespace XenAdmin.Actions.Wlb
|
||||
// Tell the user the VM will be started without HA protection.
|
||||
Program.Invoke(Program.MainWindow, delegate()
|
||||
{
|
||||
using (var dlg = new ThreeButtonDialog(
|
||||
new ThreeButtonDialog.Details(
|
||||
SystemIcons.Warning,
|
||||
String.Format(Messages.HA_INVALID_CONFIG_RESUME, Helpers.GetName(vm).Ellipsise(500)),
|
||||
Messages.HIGH_AVAILABILITY)))
|
||||
using (var dlg = new WarningDialog(String.Format(Messages.HA_INVALID_CONFIG_RESUME, Helpers.GetName(vm).Ellipsise(500)))
|
||||
{WindowTitle = Messages.HIGH_AVAILABILITY})
|
||||
{
|
||||
dlg.ShowDialog(Program.MainWindow);
|
||||
}
|
||||
@ -328,11 +315,8 @@ namespace XenAdmin.Actions.Wlb
|
||||
Helpers.GetName(vm).Ellipsise(100));
|
||||
Program.Invoke(Program.MainWindow, delegate()
|
||||
{
|
||||
using (var dlg = new ThreeButtonDialog(
|
||||
new ThreeButtonDialog.Details(
|
||||
SystemIcons.Warning,
|
||||
msg,
|
||||
Messages.HIGH_AVAILABILITY)))
|
||||
using (var dlg = new WarningDialog(msg)
|
||||
{WindowTitle = Messages.HIGH_AVAILABILITY})
|
||||
{
|
||||
dlg.ShowDialog(Program.MainWindow);
|
||||
}
|
||||
@ -347,13 +331,10 @@ namespace XenAdmin.Actions.Wlb
|
||||
|
||||
Program.Invoke(Program.MainWindow, delegate()
|
||||
{
|
||||
using (var dlg = new ThreeButtonDialog(
|
||||
new ThreeButtonDialog.Details(
|
||||
SystemIcons.Warning,
|
||||
msg,
|
||||
Messages.HIGH_AVAILABILITY),
|
||||
using (var dlg = new WarningDialog(msg,
|
||||
ThreeButtonDialog.ButtonYes,
|
||||
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, ThreeButtonDialog.ButtonType.CANCEL, true)))
|
||||
new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true))
|
||||
{WindowTitle = Messages.HIGH_AVAILABILITY})
|
||||
{
|
||||
DialogResult r = dlg.ShowDialog(Program.MainWindow);
|
||||
if (r != DialogResult.Yes)
|
||||
@ -378,7 +359,7 @@ namespace XenAdmin.Actions.Wlb
|
||||
/// <param name="recommendationId">recommendation id</param>
|
||||
private static void DoAction(AsyncAction action, VM vm, Host host, int start, int end, int recommendationId)
|
||||
{
|
||||
action.RelatedTask = XenAPI.VM.async_live_migrate(action.Session, vm.opaque_ref, host.opaque_ref);
|
||||
action.RelatedTask = VM.async_pool_migrate(action.Session, vm.opaque_ref, host.opaque_ref, new Dictionary<string, string> { ["live"] = "true" });
|
||||
|
||||
if (recommendationId != 0)
|
||||
{
|
||||
@ -403,7 +384,7 @@ namespace XenAdmin.Actions.Wlb
|
||||
/// <param name="end">progress bar end point</param>
|
||||
private static void SetHaProtection(bool protect, AsyncAction action, VM vm, int start, int end)
|
||||
{
|
||||
// Do database sync. Helps to ensure that the change persists over master failover.
|
||||
// Do database sync. Helps to ensure that the change persists over coordinator failover.
|
||||
action.RelatedTask = XenAPI.Pool.async_sync_database(action.Session);
|
||||
action.PollToCompletion(start, end);
|
||||
}
|
||||
|
@ -1,197 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Network;
|
||||
using XenAPI;
|
||||
|
||||
using XenOvf;
|
||||
using XenOvf.Definitions;
|
||||
using XenOvfTransport;
|
||||
|
||||
namespace XenAdmin.Actions.OVFActions
|
||||
{
|
||||
public class ExportApplianceAction : ApplianceAction
|
||||
{
|
||||
#region Private fields
|
||||
|
||||
private readonly string m_applianceDirectory;
|
||||
private readonly string m_applianceFileName;
|
||||
private readonly List<VM> m_vmsToExport;
|
||||
private readonly IEnumerable<string> m_eulas;
|
||||
private readonly bool m_signAppliance;
|
||||
private readonly bool m_createManifest;
|
||||
private readonly X509Certificate2 m_certificate;
|
||||
private readonly bool m_encryptFiles;
|
||||
private readonly string m_encryptPassword;
|
||||
private readonly bool m_createOVA;
|
||||
private readonly bool m_compressOVFfiles;
|
||||
private readonly bool m_shouldVerify;
|
||||
private OvfCompressor m_compressor;
|
||||
private Export m_transportAction;
|
||||
|
||||
#endregion
|
||||
|
||||
public ExportApplianceAction(IXenConnection connection, string applianceDirectory, string applianceFileName, List<VM> vmsToExport,
|
||||
IEnumerable<string> eulas, bool signAppliance, bool createManifest, X509Certificate2 certificate,
|
||||
bool encryptFiles, string encryptPassword, bool createOVA, bool compressOVFfiles,
|
||||
string networkUuid, bool isTvmIpStatic, string tvmIpAddress, string tvmSubnetMask, string tvmGateway, bool shouldVerify)
|
||||
: base(connection,
|
||||
string.Format(createOVA ? Messages.EXPORT_OVA_PACKAGE : Messages.EXPORT_OVF_PACKAGE, applianceFileName, Helpers.GetName(connection)),
|
||||
networkUuid, isTvmIpStatic, tvmIpAddress, tvmSubnetMask, tvmGateway)
|
||||
{
|
||||
m_applianceDirectory = applianceDirectory;
|
||||
m_applianceFileName = applianceFileName;
|
||||
m_vmsToExport = vmsToExport;
|
||||
m_eulas = eulas;
|
||||
m_signAppliance = signAppliance;
|
||||
m_createManifest = createManifest;
|
||||
m_certificate = certificate;
|
||||
m_encryptFiles = encryptFiles;
|
||||
m_encryptPassword = encryptPassword;
|
||||
m_createOVA = createOVA;
|
||||
m_compressOVFfiles = compressOVFfiles;
|
||||
m_shouldVerify = shouldVerify;
|
||||
|
||||
if (m_vmsToExport.Count == 1)
|
||||
VM = m_vmsToExport.First();
|
||||
}
|
||||
|
||||
protected override XenOvfTransportBase TransportAction => m_transportAction;
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
base.Run();
|
||||
|
||||
var session = Connection.Session;
|
||||
|
||||
var url = session.Url;
|
||||
Uri uri = new Uri(url);
|
||||
|
||||
var appFolder = Path.Combine(m_applianceDirectory, m_applianceFileName);
|
||||
var appFile = string.Format("{0}.ovf", m_applianceFileName);
|
||||
|
||||
if (!Directory.Exists(appFolder))
|
||||
Directory.CreateDirectory(appFolder);
|
||||
PercentComplete = 5;
|
||||
|
||||
Description = Messages.EXPORTING_VMS;
|
||||
EnvelopeType env;
|
||||
try
|
||||
{
|
||||
m_transportAction = new Export(uri, session)
|
||||
{
|
||||
UpdateHandler = UpdateHandler,
|
||||
ShouldVerifyDisks = m_shouldVerify,
|
||||
Cancel = Cancelling //in case the Cancel button has already been pressed
|
||||
};
|
||||
m_transportAction.SetTvmNetwork(m_networkUuid, m_isTvmIpStatic, m_tvmIpAddress, m_tvmSubnetMask, m_tvmGateway);
|
||||
env = m_transportAction.Process(appFolder, m_applianceFileName, (from VM vm in m_vmsToExport select vm.uuid).ToArray());
|
||||
PercentComplete = 60;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
foreach (var eula in m_eulas)
|
||||
{
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
Description = Messages.ADDING_EULAS;
|
||||
OVF.AddEula(env, eula);
|
||||
}
|
||||
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
|
||||
var ovfPath = Path.Combine(appFolder, appFile);
|
||||
Description = String.Format(Messages.CREATING_FILE, appFile);
|
||||
OVF.SaveAs(env, ovfPath);
|
||||
PercentComplete = 70;
|
||||
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
|
||||
if (m_signAppliance)
|
||||
{
|
||||
Description = Messages.SIGNING_APPLIANCE;
|
||||
OVF.Sign(m_certificate, appFolder, appFile);
|
||||
}
|
||||
else if (m_createManifest)
|
||||
{
|
||||
Description = Messages.CREATING_MANIFEST;
|
||||
OVF.Manifest(appFolder, appFile);
|
||||
}
|
||||
|
||||
PercentComplete = 90;
|
||||
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
|
||||
if (m_createOVA)
|
||||
{
|
||||
Description = String.Format(Messages.CREATING_FILE, String.Format("{0}.ova", m_applianceFileName));
|
||||
OVF.ConvertOVFtoOVA(appFolder, appFile, m_compressOVFfiles);
|
||||
}
|
||||
else if (m_compressOVFfiles)
|
||||
{
|
||||
Description = Messages.COMPRESSING_FILES;
|
||||
m_compressor = new OvfCompressor { CancelCompression = Cancelling }; //in case the Cancel button has already been pressed}
|
||||
|
||||
try
|
||||
{
|
||||
m_compressor.CompressOvfFiles(ovfPath, "GZip");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new CancelledException();
|
||||
}
|
||||
}
|
||||
|
||||
PercentComplete = 100;
|
||||
Description = Messages.COMPLETED;
|
||||
}
|
||||
|
||||
protected override void CancelRelatedTask()
|
||||
{
|
||||
base.CancelRelatedTask();
|
||||
|
||||
if (m_compressor != null)
|
||||
m_compressor.CancelCompression = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Mappings;
|
||||
using XenAdmin.Network;
|
||||
|
||||
using XenAPI;
|
||||
using XenOvf;
|
||||
using XenOvf.Definitions;
|
||||
using XenOvfTransport;
|
||||
|
||||
namespace XenAdmin.Actions.OVFActions
|
||||
{
|
||||
public class ImportApplianceAction : ApplianceAction
|
||||
{
|
||||
#region Private fields
|
||||
|
||||
private readonly Package m_package;
|
||||
private readonly Dictionary<string, VmMapping> m_vmMappings;
|
||||
private readonly bool m_verifyManifest;
|
||||
private readonly bool m_verifySignature;
|
||||
private readonly string m_password;
|
||||
private readonly bool m_runfixups;
|
||||
private readonly SR m_selectedIsoSr;
|
||||
private Import m_transportAction;
|
||||
|
||||
#endregion
|
||||
|
||||
public ImportApplianceAction(IXenConnection connection, Package package, Dictionary<string, VmMapping> vmMappings,
|
||||
bool verifyManifest, bool verifySignature, string password, bool runfixups, SR selectedIsoSr,
|
||||
string networkUuid, bool isTvmIpStatic, string tvmIpAddress, string tvmSubnetMask, string tvmGateway)
|
||||
: base(connection, string.Format(Messages.IMPORT_APPLIANCE, package.Name, Helpers.GetName(connection)),
|
||||
networkUuid, isTvmIpStatic, tvmIpAddress, tvmSubnetMask, tvmGateway)
|
||||
{
|
||||
m_package = package;
|
||||
m_vmMappings = vmMappings;
|
||||
m_verifyManifest = verifyManifest;
|
||||
m_verifySignature = verifySignature;
|
||||
m_password = password;
|
||||
m_runfixups = runfixups;
|
||||
m_selectedIsoSr = selectedIsoSr;
|
||||
}
|
||||
|
||||
protected override XenOvfTransportBase TransportAction => m_transportAction;
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
base.Run();
|
||||
|
||||
if (m_verifySignature)
|
||||
{
|
||||
Description = Messages.VERIFYING_SIGNATURE;
|
||||
|
||||
try
|
||||
{
|
||||
// The appliance is known to have a signature and the user asked to verify it.
|
||||
m_package.VerifySignature();
|
||||
|
||||
// If the appliance has a signature, then it has a manifest.
|
||||
// Always verify the manifest after verifying the signature.
|
||||
m_package.VerifyManifest();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(String.Format(Messages.VERIFYING_SIGNATURE_ERROR, e.Message));
|
||||
}
|
||||
}
|
||||
else if (m_verifyManifest)
|
||||
{
|
||||
Description = Messages.VERIFYING_MANIFEST;
|
||||
|
||||
try
|
||||
{
|
||||
// The appliance had a manifest without a signature and the user asked to verify it.
|
||||
// VerifyManifest() throws an exception when verification fails for any reason.
|
||||
m_package.VerifyManifest();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(String.Format(Messages.VERIFYING_MANIFEST_ERROR, e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
PercentComplete = 20;
|
||||
Description = Messages.IMPORTING_VMS;
|
||||
|
||||
var session = Connection.Session;
|
||||
var url = session.Url;
|
||||
Uri uri = new Uri(url);
|
||||
|
||||
//create a copy of the OVF
|
||||
var envelopes = new List<EnvelopeType>();
|
||||
|
||||
foreach (var vmMapping in m_vmMappings)
|
||||
{
|
||||
if (Cancelling)
|
||||
throw new CancelledException();
|
||||
|
||||
string systemid = vmMapping.Key;
|
||||
var mapping = vmMapping.Value;
|
||||
EnvelopeType[] envs = OVF.Split(m_package.OvfEnvelope, "system", new object[] {new[] {systemid}});
|
||||
|
||||
//storage
|
||||
foreach (var kvp in mapping.Storage)
|
||||
OVF.SetTargetSRInRASD(envs[0], systemid, kvp.Key, kvp.Value.uuid);
|
||||
|
||||
foreach (var kvp in mapping.StorageToAttach)
|
||||
OVF.SetTargetVDIInRASD(envs[0], systemid, kvp.Key, kvp.Value.uuid);
|
||||
|
||||
//network
|
||||
foreach (var kvp in mapping.Networks)
|
||||
OVF.SetTargetNetworkInRASD(envs[0], systemid, kvp.Key, kvp.Value.uuid);
|
||||
|
||||
if (m_runfixups)
|
||||
{
|
||||
string cdId = OVF.SetRunOnceBootCDROMOSFixup(envs[0], systemid, Path.GetDirectoryName(m_package.PackageSourceFile));
|
||||
OVF.SetTargetISOSRInRASD(envs[0], systemid, cdId, m_selectedIsoSr.uuid);
|
||||
}
|
||||
|
||||
envelopes.Add(envs[0]);
|
||||
}
|
||||
|
||||
EnvelopeType env = OVF.Merge(envelopes, m_package.Name);
|
||||
m_package.ExtractToWorkingDir();
|
||||
|
||||
try //importVM
|
||||
{
|
||||
m_transportAction = new Import(uri, session)
|
||||
{
|
||||
ApplianceName = m_package.Name,
|
||||
UpdateHandler = UpdateHandler,
|
||||
Cancel = Cancelling //in case the Cancel button has already been pressed
|
||||
};
|
||||
m_transportAction.SetTvmNetwork(m_networkUuid, m_isTvmIpStatic, m_tvmIpAddress, m_tvmSubnetMask, m_tvmGateway);
|
||||
m_transportAction.Process(env, m_package.WorkingDir, m_password);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new CancelledException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_package.CleanUpWorkingDir();
|
||||
}
|
||||
|
||||
PercentComplete = 100;
|
||||
Description = Messages.COMPLETED;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Mappings;
|
||||
using XenAdmin.Network;
|
||||
|
||||
using XenAPI;
|
||||
using XenOvf;
|
||||
using XenOvf.Definitions;
|
||||
using XenOvfTransport;
|
||||
|
||||
namespace XenAdmin.Actions.OVFActions
|
||||
{
|
||||
public class ImportImageAction : ApplianceAction
|
||||
{
|
||||
#region Private fields
|
||||
|
||||
private readonly EnvelopeType m_ovfEnvelope;
|
||||
private readonly Dictionary<string, VmMapping> m_vmMappings;
|
||||
private readonly bool m_runfixups;
|
||||
private readonly SR m_selectedIsoSr;
|
||||
private readonly string m_directory;
|
||||
private Import m_transportAction;
|
||||
|
||||
#endregion
|
||||
|
||||
public ImportImageAction(IXenConnection connection, EnvelopeType ovfEnv, string directory, Dictionary<string, VmMapping> vmMappings, bool runfixups, SR selectedIsoSr,
|
||||
string networkUuid, bool isTvmIpStatic, string tvmIpAddress, string tvmSubnetMask, string tvmGateway)
|
||||
: base(connection, string.Format(Messages.IMPORT_DISK_IMAGE, ovfEnv.Name, Helpers.GetName(connection)),
|
||||
networkUuid, isTvmIpStatic, tvmIpAddress, tvmSubnetMask, tvmGateway)
|
||||
{
|
||||
m_ovfEnvelope = ovfEnv;
|
||||
m_directory = directory;
|
||||
m_vmMappings = vmMappings;
|
||||
m_runfixups = runfixups;
|
||||
m_selectedIsoSr = selectedIsoSr;
|
||||
}
|
||||
|
||||
protected override XenOvfTransportBase TransportAction => m_transportAction;
|
||||
|
||||
protected override void Run()
|
||||
{
|
||||
base.Run();
|
||||
|
||||
Debug.Assert(m_vmMappings.Count == 1, "There is one VM mapping");
|
||||
|
||||
string systemid = m_vmMappings.Keys.ElementAt(0);
|
||||
var mapping = m_vmMappings.Values.ElementAt(0);
|
||||
|
||||
var session = Connection.Session;
|
||||
var url = session.Url;
|
||||
Uri uri = new Uri(url);
|
||||
|
||||
PercentComplete = 20;
|
||||
Description = Messages.IMPORTING_DISK_IMAGE;
|
||||
|
||||
//create a copy of the ovf envelope
|
||||
EnvelopeType[] envs = OVF.Split(m_ovfEnvelope, "system", new object[] {new[] {systemid}});
|
||||
EnvelopeType curEnv = envs[0];
|
||||
|
||||
//storage
|
||||
foreach (var kvp in mapping.Storage)
|
||||
OVF.SetTargetSRInRASD(curEnv, systemid, kvp.Key, kvp.Value.uuid);
|
||||
|
||||
//network
|
||||
foreach (var kvp in mapping.Networks)
|
||||
OVF.SetTargetNetworkInRASD(curEnv, systemid, kvp.Key, kvp.Value.uuid);
|
||||
|
||||
if (m_runfixups)
|
||||
{
|
||||
string cdId = OVF.SetRunOnceBootCDROMOSFixup(curEnv, systemid, m_directory);
|
||||
OVF.SetTargetISOSRInRASD(curEnv, systemid, cdId, m_selectedIsoSr.uuid);
|
||||
}
|
||||
|
||||
try //importVM
|
||||
{
|
||||
m_transportAction = new Import(uri, session)
|
||||
{
|
||||
UpdateHandler = UpdateHandler,
|
||||
Cancel = Cancelling //in case the Cancel button has already been pressed
|
||||
};
|
||||
m_transportAction.SetTvmNetwork(m_networkUuid, m_isTvmIpStatic, m_tvmIpAddress, m_tvmSubnetMask, m_tvmGateway);
|
||||
m_transportAction.Process(curEnv, m_directory, null);
|
||||
|
||||
PercentComplete = 100;
|
||||
Description = Messages.COMPLETED;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new CancelledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -78,5 +77,19 @@ namespace XenAdmin.Alerts
|
||||
date.EscapeQuotes(),
|
||||
a.WebPageLabel.EscapeQuotes());
|
||||
}
|
||||
|
||||
public static string GetGuiDate(DateTime? dateTime)
|
||||
{
|
||||
string date = string.Empty;
|
||||
|
||||
Program.Invoke(Program.MainWindow,
|
||||
() =>
|
||||
{
|
||||
if (dateTime.HasValue)
|
||||
date = HelpersGUI.DateTimeToString(dateTime.Value.ToLocalTime(), Messages.DATEFORMAT_DMY_HM, true);
|
||||
});
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -29,11 +28,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
{
|
||||
@ -44,25 +39,20 @@ namespace XenAdmin.Alerts
|
||||
if (alert1 == null || alert2 == null)
|
||||
return 0;
|
||||
|
||||
int sortResult = 0;
|
||||
|
||||
if (IsVersionOrVersionUpdateAlert(alert1) && !IsVersionOrVersionUpdateAlert(alert2))
|
||||
sortResult = 1;
|
||||
return -1;
|
||||
|
||||
if (!IsVersionOrVersionUpdateAlert(alert1) && IsVersionOrVersionUpdateAlert(alert2))
|
||||
sortResult = -1;
|
||||
return 1;
|
||||
|
||||
if (sortResult == 0)
|
||||
sortResult = Alert.CompareOnDate(alert1, alert2);
|
||||
|
||||
return -sortResult;
|
||||
return -Alert.CompareOnDate(alert1, alert2); //descending date
|
||||
}
|
||||
|
||||
private bool IsVersionOrVersionUpdateAlert(Alert alert)
|
||||
{
|
||||
return alert is XenServerPatchAlert && (alert as XenServerPatchAlert).ShowAsNewVersion
|
||||
return alert is XenServerPatchAlert xspAlert && xspAlert.ShowAsNewVersion
|
||||
|| alert is XenServerVersionAlert
|
||||
|| alert is XenCenterUpdateAlert;
|
||||
|| alert is ClientUpdateAlert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -31,12 +30,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAPI;
|
||||
using XenAdmin.TabPages;
|
||||
using XenAdmin.Dialogs;
|
||||
using System.Xml;
|
||||
using System.Text.RegularExpressions;
|
||||
using XenAdmin.Core;
|
||||
using System.Globalization;
|
||||
|
||||
@ -188,7 +184,7 @@ namespace XenAdmin.Alerts
|
||||
case AlarmType.FileSystem:
|
||||
return string.Format(Messages.ALERT_ALARM_FILESYSTEM_DESCRIPTION,
|
||||
Helpers.GetNameAndObject(XenObject),
|
||||
Util.PercentageString(CurrentValue));
|
||||
Util.PercentageString(CurrentValue), BrandManager.ProductBrand);
|
||||
case AlarmType.Memory:
|
||||
return string.Format(Messages.ALERT_ALARM_MEMORY_DESCRIPTION,
|
||||
Helpers.GetNameAndObject(XenObject),
|
||||
@ -257,29 +253,23 @@ namespace XenAdmin.Alerts
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
IXenObject xenObject = null;
|
||||
|
||||
if (XenObject is Host) //sr is only set when it's AlarmType.Storage
|
||||
xenObject = sr ?? XenObject;
|
||||
else if (XenObject is VM vm)
|
||||
xenObject = vm.IsControlDomainZero(out Host host) ? host : XenObject;
|
||||
|
||||
if (xenObject == null)
|
||||
return;
|
||||
|
||||
using (var dialog = new PropertiesDialog(xenObject) {TopMost = true})
|
||||
{
|
||||
IXenObject xenObject = null;
|
||||
|
||||
if (XenObject is Host)
|
||||
{
|
||||
//sr is only set when it's AlarmType.Storage
|
||||
xenObject = sr ?? XenObject;
|
||||
}
|
||||
else if (XenObject is VM)
|
||||
{
|
||||
VM vm = (VM)XenObject;
|
||||
xenObject = vm.IsControlDomainZero() ? XenObject.Connection.Resolve(vm.resident_on) : XenObject;
|
||||
}
|
||||
|
||||
if (xenObject == null)
|
||||
return;
|
||||
|
||||
using (var dialog = new PropertiesDialog(xenObject) { TopMost = true })
|
||||
{
|
||||
dialog.SelectPerfmonAlertEditPage();
|
||||
dialog.ShowDialog(Program.MainWindow);
|
||||
}
|
||||
};
|
||||
dialog.SelectPerfmonAlertEditPage();
|
||||
dialog.ShowDialog(Program.MainWindow);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
244
XenAdmin/Alerts/Types/CertificateAlert.cs
Normal file
@ -0,0 +1,244 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using XenAdmin.Commands;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
{
|
||||
public class CertificateAlert : MessageAlert
|
||||
{
|
||||
private readonly DateTime? _certificateExpiryDate;
|
||||
|
||||
public CertificateAlert(Message m)
|
||||
: base(m)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(m.body);
|
||||
var nodes = doc.GetElementsByTagName("date");
|
||||
|
||||
if (nodes.Count > 0 && Util.TryParseIso8601DateTime(nodes[0].InnerText, out DateTime result))
|
||||
_certificateExpiryDate = result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
public override string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
var objectName = XenObject == null ? Messages.UNKNOWN_OBJECT : XenObject.Name();
|
||||
|
||||
switch (Message.Type)
|
||||
{
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRED:
|
||||
var pool1 = Helpers.GetPoolOfOne(Connection);
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRED_TITLE, objectName, pool1.Name());
|
||||
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_30:
|
||||
var pool2 = Helpers.GetPoolOfOne(Connection);
|
||||
if (_certificateExpiryDate.HasValue && _certificateExpiryDate.Value > Timestamp)
|
||||
{
|
||||
var eta = _certificateExpiryDate.Value - Timestamp;
|
||||
|
||||
if (eta.TotalDays >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRING_TITLE_DAYS, objectName,
|
||||
pool2.Name(), Math.Round(eta.TotalDays, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalHours >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRING_TITLE_HOURS, objectName,
|
||||
pool2.Name(), Math.Round(eta.TotalHours, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalMinutes >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRING_TITLE_MINUTES, objectName,
|
||||
pool2.Name(), Math.Round(eta.TotalMinutes, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRED_TITLE, objectName, pool2.Name());
|
||||
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRED:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRED_TITLE, objectName);
|
||||
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_30:
|
||||
if (_certificateExpiryDate.HasValue && _certificateExpiryDate.Value > Timestamp)
|
||||
{
|
||||
var eta = _certificateExpiryDate.Value - Timestamp;
|
||||
|
||||
if (eta.TotalDays >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRING_TITLE_DAYS, objectName,
|
||||
Math.Round(eta.TotalDays, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalHours >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRING_TITLE_HOURS, objectName,
|
||||
Math.Round(eta.TotalHours, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalMinutes >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRING_TITLE_MINUTES, objectName,
|
||||
Math.Round(eta.TotalMinutes, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRED_TITLE, objectName);
|
||||
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRED:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRED_TITLE, objectName);
|
||||
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_30:
|
||||
if (_certificateExpiryDate.HasValue && _certificateExpiryDate.Value > Timestamp)
|
||||
{
|
||||
var eta = _certificateExpiryDate.Value - Timestamp;
|
||||
|
||||
if (eta.TotalDays >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRING_TITLE_DAYS, objectName,
|
||||
Math.Round(eta.TotalDays, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalHours >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRING_TITLE_HOURS, objectName,
|
||||
Math.Round(eta.TotalHours, MidpointRounding.AwayFromZero));
|
||||
|
||||
if (eta.TotalMinutes >= 1)
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRING_TITLE_MINUTES, objectName,
|
||||
Math.Round(eta.TotalMinutes, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRED_TITLE, objectName);
|
||||
|
||||
default:
|
||||
return base.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
var objectName = XenObject == null ? Messages.UNKNOWN_OBJECT : XenObject.Name();
|
||||
|
||||
switch (Message.Type)
|
||||
{
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRED:
|
||||
var pool1 = Helpers.GetPoolOfOne(Connection);
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRED_DESCIRPTION, objectName, pool1.Name(),
|
||||
AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.POOL_CA_CERTIFICATE_EXPIRING_30:
|
||||
var pool2 = Helpers.GetPoolOfOne(Connection);
|
||||
return string.Format(Messages.CERTIFICATE_CA_ALERT_EXPIRING_DESCRIPTION,
|
||||
objectName, pool2.Name(), AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRED:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRED_DESCIRPTION,
|
||||
objectName, AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_INTERNAL_CERTIFICATE_EXPIRING_30:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_INTERNAL_ALERT_EXPIRING_DESCRIPTION,
|
||||
objectName, AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRED:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRED_DESCIRPTION, objectName,
|
||||
AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_30:
|
||||
return string.Format(Messages.CERTIFICATE_HOST_ALERT_EXPIRING_DESCRIPTION,
|
||||
objectName, AlertExtensions.GetGuiDate(_certificateExpiryDate));
|
||||
|
||||
default:
|
||||
return base.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Action FixLinkAction
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!(XenObject is Host host))
|
||||
return null;
|
||||
|
||||
switch (Message.Type)
|
||||
{
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRED:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_30:
|
||||
var cmd = new InstallCertificateCommand(Program.MainWindow, host);
|
||||
if (cmd.CanRun())
|
||||
return () => cmd.Run();
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string FixLinkText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!(XenObject is Host))
|
||||
return null;
|
||||
|
||||
switch (Message.Type)
|
||||
{
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRED:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_07:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_14:
|
||||
case Message.MessageType.HOST_SERVER_CERTIFICATE_EXPIRING_30:
|
||||
return Messages.INSTALL_SERVER_CERTIFICATE_ACTION_LINK;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string HelpID => "CertificateAlert";
|
||||
|
||||
public override string HelpLinkText => Messages.ALERT_GENERIC_HELP;
|
||||
}
|
||||
}
|
187
XenAdmin/Alerts/Types/ClientUpdateAlert.cs
Normal file
@ -0,0 +1,187 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using XenAdmin.Actions;
|
||||
using XenAdmin.Actions.GUIActions;
|
||||
using XenAdmin.Actions.Updates;
|
||||
using XenAdmin.Core;
|
||||
using XenAdmin.Dialogs;
|
||||
using XenAdmin.Dialogs.WarningDialogs;
|
||||
using XenCenterLib;
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
{
|
||||
public class ClientUpdateAlert : Alert
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public readonly ClientVersion NewVersion;
|
||||
|
||||
public ClientUpdateAlert(ClientVersion version)
|
||||
{
|
||||
NewVersion = version;
|
||||
_timestamp = NewVersion.TimeStamp;
|
||||
Checksum = version.Checksum;
|
||||
}
|
||||
|
||||
public override AlertPriority Priority => AlertPriority.Priority5;
|
||||
|
||||
public override string WebPageLabel => InvisibleMessages.RELEASE_NOTES_URL;
|
||||
|
||||
public override string Name => NewVersion.Name;
|
||||
|
||||
public override string Title => string.Format(Messages.ALERT_NEW_VERSION, NewVersion.Name);
|
||||
|
||||
public override string Description => string.Format(Messages.ALERT_NEW_VERSION_DETAILS_CLIENT,
|
||||
NewVersion.Name);
|
||||
|
||||
public override Action FixLinkAction
|
||||
{
|
||||
get { return () => Program.OpenURL(WebPageLabel); }
|
||||
}
|
||||
|
||||
public override string FixLinkText => string.Format(Messages.ALERT_NEW_VERSION_DOWNLOAD_CLIENT, NewVersion.Version);
|
||||
|
||||
public override string AppliesTo => BrandManager.BrandConsole;
|
||||
|
||||
public override string HelpID => "XenCenterUpdateAlert";
|
||||
|
||||
public string Checksum { get; }
|
||||
|
||||
public override bool AllowedToDismiss()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Dismiss()
|
||||
{
|
||||
//do not dismiss this alert
|
||||
}
|
||||
|
||||
public override bool Equals(Alert other)
|
||||
{
|
||||
if (other is ClientUpdateAlert clientAlert)
|
||||
return NewVersion.VersionAndLang == clientAlert.NewVersion.VersionAndLang;
|
||||
|
||||
return base.Equals(other);
|
||||
}
|
||||
|
||||
public static void DownloadAndInstallNewClient(ClientUpdateAlert updateAlert, IWin32Window parent)
|
||||
{
|
||||
var outputPathAndFileName = Path.Combine(Path.GetTempPath(), $"{BrandManager.BrandConsole}.msi");
|
||||
|
||||
var downloadAndInstallClientAction = new DownloadAndUpdateClientAction(updateAlert.Name, new Uri(updateAlert.NewVersion.Url), outputPathAndFileName, updateAlert.Checksum);
|
||||
|
||||
using (var dlg = new ActionProgressDialog(downloadAndInstallClientAction, ProgressBarStyle.Continuous))
|
||||
{
|
||||
dlg.ShowCancel = true;
|
||||
dlg.ShowDialog(parent);
|
||||
}
|
||||
|
||||
if (!downloadAndInstallClientAction.Succeeded)
|
||||
return;
|
||||
|
||||
bool currentTasks = false;
|
||||
foreach (ActionBase a in ConnectionsManager.History)
|
||||
{
|
||||
if (a is MeddlingAction || a.IsCompleted)
|
||||
continue;
|
||||
|
||||
currentTasks = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTasks)
|
||||
{
|
||||
using (var dlg = new CloseXenCenterWarningDialog(true))
|
||||
{
|
||||
if (dlg.ShowDialog(parent) != DialogResult.OK)
|
||||
{
|
||||
downloadAndInstallClientAction.ReleaseDownloadedContent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(outputPathAndFileName);
|
||||
log.DebugFormat("Update {0} found and install started", updateAlert.Name);
|
||||
downloadAndInstallClientAction.ReleaseDownloadedContent();
|
||||
Application.Exit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Exception occurred when starting the installation process.", e);
|
||||
downloadAndInstallClientAction.ReleaseDownloadedContent(true);
|
||||
|
||||
using (var dlg = new ErrorDialog(Messages.UPDATE_CLIENT_FAILED_INSTALLER_LAUNCH))
|
||||
dlg.ShowDialog(parent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DownloadSource(IWin32Window parent)
|
||||
{
|
||||
// If no update no need to show where to save dialog
|
||||
var clientVersion = Updates.ClientVersions.FirstOrDefault();
|
||||
|
||||
if (clientVersion == null)
|
||||
{
|
||||
// There is no XCUpdates.xml so direct to website.
|
||||
Program.OpenURL(InvisibleMessages.WEBSITE_DOWNLOADS);
|
||||
}
|
||||
else
|
||||
{
|
||||
string outputPathAndFileName;
|
||||
using (var saveSourceDialog = new SaveFileDialog())
|
||||
{
|
||||
saveSourceDialog.FileName = $"{BrandManager.BrandConsole}-v{clientVersion.Version}-source.zip";
|
||||
saveSourceDialog.DefaultExt = "zip";
|
||||
saveSourceDialog.Filter = "(*.zip)|*.zip|All files (*.*)|*.*";
|
||||
saveSourceDialog.InitialDirectory = Win32.GetKnownFolderPath(Win32.KnownFolders.Downloads);
|
||||
|
||||
if (saveSourceDialog.ShowDialog(parent) != DialogResult.OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
outputPathAndFileName = saveSourceDialog.FileName;
|
||||
}
|
||||
|
||||
var downloadSourceAction = new DownloadSourceAction(clientVersion.Name, new Uri(clientVersion.SourceUrl), outputPathAndFileName);
|
||||
downloadSourceAction.RunAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
XenAdmin/Alerts/Types/CssExpiryAlert.cs
Normal file
@ -0,0 +1,108 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Xml;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
{
|
||||
public class CssExpiryAlert : MessageAlert
|
||||
{
|
||||
private readonly DateTime? _cssExpiryDate;
|
||||
private readonly string _title;
|
||||
private readonly string _description;
|
||||
|
||||
public CssExpiryAlert(Message m)
|
||||
: base(m)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(m.body);
|
||||
var nodes = doc.GetElementsByTagName("date");
|
||||
|
||||
if (nodes.Count > 0 && Util.TryParseIso8601DateTime(nodes[0].InnerText, out var result))
|
||||
_cssExpiryDate = result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
|
||||
switch (Message.Type)
|
||||
{
|
||||
case Message.MessageType.UPDATES_FEATURE_EXPIRED:
|
||||
_title = Messages.ALERT_CSS_EXPIRED_TITLE;
|
||||
_description = string.Format(Messages.ALERT_CSS_EXPIRED_DESCIRPTION, AlertExtensions.GetGuiDate(_cssExpiryDate));
|
||||
break;
|
||||
|
||||
case Message.MessageType.UPDATES_FEATURE_EXPIRING_CRITICAL:
|
||||
case Message.MessageType.UPDATES_FEATURE_EXPIRING_MAJOR:
|
||||
case Message.MessageType.UPDATES_FEATURE_EXPIRING_WARNING:
|
||||
|
||||
if (_cssExpiryDate.HasValue && _cssExpiryDate.Value > Timestamp)
|
||||
{
|
||||
var eta = _cssExpiryDate.Value - Timestamp;
|
||||
|
||||
if (eta.TotalDays >= 1)
|
||||
_title = string.Format(Messages.ALERT_CSS_EXPIRING_TITLE_DAYS, Math.Round(eta.TotalDays, MidpointRounding.AwayFromZero));
|
||||
|
||||
else if (eta.TotalHours >= 1)
|
||||
_title = string.Format(Messages.ALERT_CSS_EXPIRING_TITLE_HOURS, Math.Round(eta.TotalHours, MidpointRounding.AwayFromZero));
|
||||
|
||||
else if (eta.TotalMinutes >= 1)
|
||||
_title = string.Format(Messages.ALERT_CSS_EXPIRING_TITLE_MINUTES, Math.Round(eta.TotalMinutes, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
else
|
||||
{
|
||||
_title = Messages.ALERT_CSS_EXPIRED_TITLE;
|
||||
}
|
||||
|
||||
_description = string.Format(Messages.ALERT_CSS_EXPIRING_DESCRIPTION, AlertExtensions.GetGuiDate(_cssExpiryDate));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Title => string.IsNullOrEmpty(_title) ? base.Title : _title;
|
||||
|
||||
public override string Description => string.IsNullOrEmpty(_description) ? base.Title : _description;
|
||||
|
||||
public override Action FixLinkAction => () => Process.Start(InvisibleMessages.CSS_URL);
|
||||
|
||||
public override string FixLinkText => Messages.ALERT_CSS_EXPIRED_LINK_TEXT;
|
||||
|
||||
public override string HelpID => "CssExpiryAlert";
|
||||
|
||||
public override string HelpLinkText => Messages.ALERT_GENERIC_HELP;
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
|
203
XenAdmin/Alerts/Types/FailedLoginAttemptAlert.cs
Normal file
@ -0,0 +1,203 @@
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using XenAdmin.Core;
|
||||
using XenAPI;
|
||||
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
{
|
||||
public class FailedLoginAttemptAlert : MessageAlert
|
||||
{
|
||||
private readonly Pool _pool;
|
||||
private readonly int _total;
|
||||
private readonly int _unknown;
|
||||
private readonly List<Offender> _topOffenders = new List<Offender>();
|
||||
|
||||
public FailedLoginAttemptAlert(Message m)
|
||||
: base(m)
|
||||
{
|
||||
_pool = m.Connection.Cache.Pools.FirstOrDefault(p => p.uuid == m.obj_uuid);
|
||||
|
||||
try
|
||||
{
|
||||
/* - Total and unknown are optional (unknown being absent implies that all the failed
|
||||
logins came from known sources, and conversely total being absent implies that all
|
||||
the failed logins came from unknown sources).
|
||||
- There may be 0 or more known tags.
|
||||
- Each known tag must contain date and number, but the other tags (ip, originator,
|
||||
username, useragent) are all optional (though we expect at least one) */
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(m.body);
|
||||
|
||||
var totalNodes = doc.GetElementsByTagName("total");
|
||||
if (totalNodes.Count > 0)
|
||||
int.TryParse(totalNodes[0].InnerText, out _total);
|
||||
|
||||
var unknownNodes = doc.GetElementsByTagName("unknown");
|
||||
if (unknownNodes.Count > 0)
|
||||
int.TryParse(unknownNodes[0].InnerText, out _unknown);
|
||||
|
||||
var knownNodes = doc.GetElementsByTagName("known");
|
||||
foreach (XmlNode node in knownNodes)
|
||||
{
|
||||
var offender = new Offender();
|
||||
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
switch (child.Name)
|
||||
{
|
||||
case "number":
|
||||
if (int.TryParse(child.InnerText, out var number))
|
||||
offender.Number = number;
|
||||
break;
|
||||
case "date":
|
||||
if (Util.TryParseIso8601DateTime(child.InnerText, out var date))
|
||||
offender.Date = date;
|
||||
break;
|
||||
case "ip":
|
||||
offender.Ip = child.InnerText;
|
||||
break;
|
||||
case "originator":
|
||||
offender.Originator = child.InnerText;
|
||||
break;
|
||||
case "username":
|
||||
offender.Username = child.InnerText;
|
||||
break;
|
||||
case "useragent":
|
||||
offender.Useragent = child.InnerText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_topOffenders.Add(offender);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
public override string Title => _pool == null
|
||||
? base.Title
|
||||
: string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_TITLE, _pool.Name());
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_total == 0 && _unknown > 0)
|
||||
return string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_DESCRIPTION_ALL_UNKNOWN, _unknown);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (_total > 0)
|
||||
sb.AppendLine(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_DESCRIPTION_TOTAL, _total));
|
||||
|
||||
if (_unknown > 0)
|
||||
sb.AppendLine(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_DESCRIPTION_UNKNOWN, _unknown));
|
||||
|
||||
if (_topOffenders.Count > 0)
|
||||
{
|
||||
sb.AppendLine(Messages.ALERT_FAILED_LOGIN_ATTEMPT_DESCRIPTION_COMMON);
|
||||
|
||||
foreach (var offender in _topOffenders)
|
||||
sb.AppendLine(offender.ToString());
|
||||
}
|
||||
|
||||
return sb.Length > 0 ? sb.ToString() : base.Title;
|
||||
}
|
||||
}
|
||||
|
||||
public override Action FixLinkAction => null;
|
||||
|
||||
public override string FixLinkText => null;
|
||||
|
||||
public override string HelpID => "FailedLoginAttemptAlert";
|
||||
|
||||
public override string HelpLinkText => Messages.ALERT_GENERIC_HELP;
|
||||
|
||||
|
||||
private class Offender
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of failed login attempts from this offender
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DateTime of last failed login attempt from this offender
|
||||
/// </summary>
|
||||
public DateTime? Date { private get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Offender IP address
|
||||
/// </summary>
|
||||
public string Ip { get; set;}
|
||||
|
||||
public string Originator { get; set;}
|
||||
public string Username { get; set;}
|
||||
public string Useragent { get; set;}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var entries = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Ip))
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_IP, Ip));
|
||||
|
||||
if (Number > 0)
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_NUMBER, Number));
|
||||
|
||||
var friendlyDate = AlertExtensions.GetGuiDate(Date);
|
||||
if (!string.IsNullOrEmpty(friendlyDate))
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_DATE, friendlyDate));
|
||||
|
||||
if (!string.IsNullOrEmpty(Username))
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_USERNAME, Username));
|
||||
|
||||
if (!string.IsNullOrEmpty(Originator))
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_ORIGINATOR, Originator));
|
||||
|
||||
if (!string.IsNullOrEmpty(Useragent))
|
||||
entries.Add(string.Format(Messages.ALERT_FAILED_LOGIN_ATTEMPT_OFFENDER_USERAGENT, Useragent));
|
||||
|
||||
return $"- {string.Join(", ", entries)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -30,8 +29,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using XenAdmin.Core;
|
||||
|
||||
|
||||
namespace XenAdmin.Alerts
|
||||
@ -43,51 +41,21 @@ namespace XenAdmin.Alerts
|
||||
_timestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
public override AlertPriority Priority { get { return AlertPriority.Priority5; } }
|
||||
public override AlertPriority Priority => AlertPriority.Priority5;
|
||||
|
||||
public override string AppliesTo
|
||||
{
|
||||
get
|
||||
{
|
||||
return Messages.XENCENTER;
|
||||
}
|
||||
}
|
||||
public override string AppliesTo => BrandManager.BrandConsole;
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Messages.NEWER_GUI_AVAILABLE;
|
||||
}
|
||||
}
|
||||
public override string Description => string.Format(Messages.NEWER_GUI_AVAILABLE, BrandManager.BrandConsole);
|
||||
|
||||
public override Action FixLinkAction
|
||||
{
|
||||
get { return () => Program.OpenURL(InvisibleMessages.OUT_OF_DATE_WEBSITE); }
|
||||
get { return () => Program.OpenURL(InvisibleMessages.WEBSITE_DOWNLOADS); }
|
||||
}
|
||||
|
||||
public override string FixLinkText
|
||||
{
|
||||
get
|
||||
{
|
||||
return Messages.ALERT_NEW_VERSION_DOWNLOAD;
|
||||
}
|
||||
}
|
||||
public override string FixLinkText => Messages.ALERT_NEW_VERSION_DOWNLOAD;
|
||||
|
||||
public override string HelpID
|
||||
{
|
||||
get
|
||||
{
|
||||
return "GuiOldAlert";
|
||||
}
|
||||
}
|
||||
public override string HelpID => "GuiOldAlert";
|
||||
|
||||
public override string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return Messages.XENCENTER_NEWER_AVAILABLE;
|
||||
}
|
||||
}
|
||||
public override string Title => string.Format(Messages.XENCENTER_NEWER_AVAILABLE, BrandManager.BrandConsole);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) Citrix Systems, Inc.
|
||||
* All rights reserved.
|
||||
/* Copyright (c) Cloud Software Group, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -44,7 +43,7 @@ namespace XenAdmin.Alerts.Types
|
||||
public HotfixEligibilityAlert(IXenConnection connection, XenServerVersion version)
|
||||
{
|
||||
Connection = connection;
|
||||
this.Version = version;
|
||||
Version = version;
|
||||
pool = Helpers.GetPoolOfOne(connection);
|
||||
_timestamp = DateTime.Now;
|
||||
}
|
||||
@ -59,8 +58,8 @@ namespace XenAdmin.Alerts.Types
|
||||
return string.Empty;
|
||||
|
||||
var productVersionText = string.Format(Messages.STRING_SPACE_STRING,
|
||||
Helpers.NaplesOrGreater(Connection) ? Messages.XENSERVER : BrandManager.LegacyProduct,
|
||||
Helpers.GetMaster(Connection)?.ProductVersionText());
|
||||
!Helpers.NaplesOrGreater(Connection) || Helpers.CloudOrGreater(Connection) ? BrandManager.ProductBrand : BrandManager.LegacyProduct,
|
||||
Helpers.GetCoordinator(Connection)?.ProductVersionText());
|
||||
var unlicensed = pool.IsFreeLicenseOrExpired();
|
||||
|
||||
switch (Version.HotfixEligibility)
|
||||
@ -68,7 +67,7 @@ namespace XenAdmin.Alerts.Types
|
||||
// all + the EOL date is known -> "Approaching EOL" alert
|
||||
case hotfix_eligibility.all when Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_TITLE_APPROACHING_EOL,
|
||||
productVersionText, GetEolDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate));
|
||||
|
||||
// premium + unlicensed host -> "EOL for express customers" alert
|
||||
case hotfix_eligibility.premium when unlicensed:
|
||||
@ -77,7 +76,7 @@ namespace XenAdmin.Alerts.Types
|
||||
// premium + licensed host and the EOL date is known -> "Approaching EOL" alert
|
||||
case hotfix_eligibility.premium when Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_TITLE_APPROACHING_EOL,
|
||||
productVersionText, GetEolDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate));
|
||||
|
||||
// cu -> "EOL for express customers" / "CU for licensed customers" alert
|
||||
case hotfix_eligibility.cu when pool.IsFreeLicenseOrExpired():
|
||||
@ -103,9 +102,9 @@ namespace XenAdmin.Alerts.Types
|
||||
if (pool == null)
|
||||
return string.Empty;
|
||||
|
||||
var versionText = Helpers.GetMaster(Connection)?.ProductVersionText();
|
||||
var productVersionText = string.Format(Messages.STRING_SPACE_STRING,
|
||||
Helpers.NaplesOrGreater(Connection) ? Messages.XENSERVER : BrandManager.LegacyProduct,
|
||||
var versionText = Helpers.GetCoordinator(Connection)?.ProductVersionText();
|
||||
var productVersionText = string.Format(Messages.STRING_SPACE_STRING,
|
||||
!Helpers.NaplesOrGreater(Connection) || Helpers.CloudOrGreater(Connection) ? BrandManager.ProductBrand : BrandManager.LegacyProduct,
|
||||
versionText);
|
||||
var unlicensed = pool.IsFreeLicenseOrExpired();
|
||||
|
||||
@ -114,36 +113,36 @@ namespace XenAdmin.Alerts.Types
|
||||
// all + the EOL date is known -> "Approaching EOL" alert
|
||||
case hotfix_eligibility.all when unlicensed && Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_APPROACHING_EOL_FREE,
|
||||
productVersionText, GetEolDate(), versionText);
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate), versionText);
|
||||
case hotfix_eligibility.all when Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_APPROACHING_EOL,
|
||||
productVersionText, GetEolDate(), versionText);
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate), versionText);
|
||||
|
||||
// premium + unlicensed host -> "EOL for express customers" alert
|
||||
case hotfix_eligibility.premium when unlicensed && Version.HotfixEligibilityPremiumDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_FREE,
|
||||
productVersionText, GetPremiumDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.HotfixEligibilityPremiumDate));
|
||||
|
||||
// premium + licensed host and the EOL date is known -> "Approaching EOL" alert
|
||||
case hotfix_eligibility.premium when !unlicensed && Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_APPROACHING_EOL,
|
||||
productVersionText, GetEolDate(), versionText);
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate), versionText);
|
||||
|
||||
// cu -> "EOL for express customers" / "CU for licensed customers" alert
|
||||
case hotfix_eligibility.cu when unlicensed && Version.HotfixEligibilityPremiumDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_FREE,
|
||||
productVersionText, GetPremiumDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.HotfixEligibilityPremiumDate));
|
||||
case hotfix_eligibility.cu when !unlicensed && Version.HotfixEligibilityNoneDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_CU, productVersionText,
|
||||
GetNoneDate(), versionText);
|
||||
AlertExtensions.GetGuiDate(Version.HotfixEligibilityNoneDate), versionText);
|
||||
|
||||
// none -> EOL alert
|
||||
case hotfix_eligibility.none when unlicensed && Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_EOL_FREE,
|
||||
productVersionText, GetEolDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate));
|
||||
case hotfix_eligibility.none when Version.EolDate != DateTime.MinValue:
|
||||
return string.Format(Messages.HOTFIX_ELIGIBILITY_ALERT_DESCRIPTION_EOL,
|
||||
productVersionText, GetEolDate());
|
||||
productVersionText, AlertExtensions.GetGuiDate(Version.EolDate));
|
||||
|
||||
// everything else
|
||||
default:
|
||||
@ -202,44 +201,5 @@ namespace XenAdmin.Alerts.Types
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetEolDate()
|
||||
{
|
||||
string date = string.Empty;
|
||||
|
||||
Program.Invoke(Program.MainWindow, () =>
|
||||
{
|
||||
date = HelpersGUI.DateTimeToString(Version.EolDate.ToLocalTime(), Messages.DATEFORMAT_DMY, true);
|
||||
});
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
private string GetPremiumDate()
|
||||
{
|
||||
string date = string.Empty;
|
||||
|
||||
Program.Invoke(Program.MainWindow, () =>
|
||||
{
|
||||
date = HelpersGUI.DateTimeToString(Version.HotfixEligibilityPremiumDate.ToLocalTime(),
|
||||
Messages.DATEFORMAT_DMY, true);
|
||||
});
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
private string GetNoneDate()
|
||||
{
|
||||
string date = string.Empty;
|
||||
|
||||
Program.Invoke(Program.MainWindow, () =>
|
||||
{
|
||||
date = HelpersGUI.DateTimeToString(Version.HotfixEligibilityNoneDate.ToLocalTime(),
|
||||
Messages.DATEFORMAT_DMY, true);
|
||||
});
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|