diff --git a/docs/themes/sphinx_rtd_theme/static/css/theme.css b/docs/themes/sphinx_rtd_theme/static/css/theme.css
index a2d7c0f..bfe901f 100644
--- a/docs/themes/sphinx_rtd_theme/static/css/theme.css
+++ b/docs/themes/sphinx_rtd_theme/static/css/theme.css
@@ -1,5 +1,6489 @@
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*!
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block
+}
+
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1
+}
+
+audio:not([controls]) {
+ display: none
+}
+
+[hidden] {
+ display: none
+}
+
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box
+}
+
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%
+}
+
+body {
+ margin: 0
+}
+
+a:hover,
+a:active {
+ outline: 0
+}
+
+abbr[title] {
+ border-bottom: 1px dotted
+}
+
+b,
+strong {
+ font-weight: bold
+}
+
+blockquote {
+ margin: 0
+}
+
+dfn {
+ font-style: italic
+}
+
+ins {
+ background: #ff9;
+ color: #000;
+ text-decoration: none
+}
+
+mark {
+ background: #ff0;
+ color: #000;
+ font-style: italic;
+ font-weight: bold
+}
+
+pre,
+code,
+.rst-content tt,
+.rst-content code,
+kbd,
+samp {
+ font-family: monospace, serif;
+ _font-family: "courier new", monospace;
+ font-size: 1em
+}
+
+pre {
+ white-space: pre
+}
+
+q {
+ quotes: none
+}
+
+q:before,
+q:after {
+ content: "";
+ content: none
+}
+
+small {
+ font-size: 85%
+}
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline
+}
+
+sup {
+ top: -0.5em
+}
+
+sub {
+ bottom: -0.25em
+}
+
+ul,
+ol,
+dl {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ list-style-image: none
+}
+
+li {
+ list-style: none
+}
+
+dd {
+ margin: 0
+}
+
+img {
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+ vertical-align: middle;
+ max-width: 100%
+}
+
+svg:not(:root) {
+ overflow: hidden
+}
+
+figure {
+ margin: 0
+}
+
+form {
+ margin: 0
+}
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0
+}
+
+label {
+ cursor: pointer
+}
+
+legend {
+ border: 0;
+ *margin-left: -7px;
+ padding: 0;
+ white-space: normal
+}
+
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+ margin: 0;
+ vertical-align: baseline;
+ *vertical-align: middle
+}
+
+button,
+input {
+ line-height: normal
+}
+
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+ *overflow: visible
+}
+
+button[disabled],
+input[disabled] {
+ cursor: default
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box;
+ padding: 0;
+ *width: 13px;
+ *height: 13px
+}
+
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0
+}
+
+textarea {
+ overflow: auto;
+ vertical-align: top;
+ resize: vertical
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0
+}
+
+td {
+ vertical-align: top
+}
+
+.chromeframe {
+ margin: 0.2em 0;
+ background: #ccc;
+ color: #000;
+ padding: 0.2em 0
+}
+
+.ir {
+ display: block;
+ border: 0;
+ text-indent: -999em;
+ overflow: hidden;
+ background-color: transparent;
+ background-repeat: no-repeat;
+ text-align: left;
+ direction: ltr;
+ *line-height: 0
+}
+
+.ir br {
+ display: none
+}
+
+.hidden {
+ display: none !important;
+ visibility: hidden
+}
+
+.visuallyhidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px
+}
+
+.visuallyhidden.focusable:active,
+.visuallyhidden.focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ width: auto
+}
+
+.invisible {
+ visibility: hidden
+}
+
+.relative {
+ position: relative
+}
+
+big,
+small {
+ font-size: 100%
+}
+
+@media print {
+
+ html,
+ body,
+ section {
+ background: none !important
+ }
+
+ * {
+ box-shadow: none !important;
+ text-shadow: none !important;
+ filter: none !important;
+ -ms-filter: none !important
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline
+ }
+
+ .ir a:after,
+ a[href^="javascript:"]:after,
+ a[href^="#"]:after {
+ content: ""
+ }
+
+ pre,
+ blockquote {
+ page-break-inside: avoid
+ }
+
+ thead {
+ display: table-header-group
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid
+ }
+
+ img {
+ max-width: 100% !important
+ }
+
+ @page {
+ margin: 0.5cm
+ }
+
+ p,
+ h2,
+ .rst-content .toctree-wrapper p.caption,
+ h3 {
+ orphans: 3;
+ widows: 3
+ }
+
+ h2,
+ .rst-content .toctree-wrapper p.caption,
+ h3 {
+ page-break-after: avoid
+ }
+}
+
+.fa:before,
+.wy-menu-vertical li span.toctree-expand:before,
+.wy-menu-vertical li.on a span.toctree-expand:before,
+.wy-menu-vertical li.current>a span.toctree-expand:before,
+.rst-content .admonition-title:before,
+.rst-content h1 .headerlink:before,
+.rst-content h2 .headerlink:before,
+.rst-content h3 .headerlink:before,
+.rst-content h4 .headerlink:before,
+.rst-content h5 .headerlink:before,
+.rst-content h6 .headerlink:before,
+.rst-content dl dt .headerlink:before,
+.rst-content p.caption .headerlink:before,
+.rst-content tt.download span:first-child:before,
+.rst-content code.download span:first-child:before,
+.icon:before,
+.wy-dropdown .caret:before,
+.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,
+.wy-alert,
+.rst-content .note,
+.rst-content .attention,
+.rst-content .caution,
+.rst-content .danger,
+.rst-content .error,
+.rst-content .hint,
+.rst-content .important,
+.rst-content .tip,
+.rst-content .warning,
+.rst-content .seealso,
+.rst-content .admonition-todo,
+.btn,
+input[type="text"],
+input[type="password"],
+input[type="email"],
+input[type="url"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="week"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+select,
+textarea,
+.wy-menu-vertical li.on a,
+.wy-menu-vertical li.current>a,
+.wy-side-nav-search>a,
+.wy-side-nav-search .wy-dropdown>a,
+.wy-nav-top a {
+ -webkit-font-smoothing: antialiased
+}
+
+.clearfix {
+ *zoom: 1
+}
+
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: ""
+}
+
+.clearfix:after {
+ clear: both
+}
+
+/*!
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#555;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:0.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:0.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:0.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:0.4045em 5.663em;border-top:none;border-bottom:none}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:0.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#b3b3b3}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:0.809em;margin-bottom:0.809em;z-index:200;background-color:#2980B9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-side-nav-search>div.version{margin-top:-0.4045em;margin-bottom:0.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:#999}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content .toctree-wrapper p.caption:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink,.rst-content p.caption:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt,.rst-content tt,.rst-content code{color:#000;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),local("Inconsolata-Regular"),url(../fonts/Inconsolata-Regular.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")}
-/*# sourceMappingURL=theme.css.map */
+ */
+@font-face {
+ font-family: 'FontAwesome';
+ src: url("../fonts/fontawesome-webfont.eot?v=4.2.0");
+ src: url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"), url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"), url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");
+ font-weight: normal;
+ font-style: normal
+}
+
+.fa,
+.wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.current>a span.toctree-expand,
+.rst-content .admonition-title,
+.rst-content h1 .headerlink,
+.rst-content h2 .headerlink,
+.rst-content h3 .headerlink,
+.rst-content h4 .headerlink,
+.rst-content h5 .headerlink,
+.rst-content h6 .headerlink,
+.rst-content dl dt .headerlink,
+.rst-content p.caption .headerlink,
+.rst-content tt.download span:first-child,
+.rst-content code.download span:first-child,
+.icon {
+ display: inline-block;
+ font: normal normal normal 14px/1 FontAwesome;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale
+}
+
+.fa-lg {
+ font-size: 1.33333em;
+ line-height: 0.75em;
+ vertical-align: -15%
+}
+
+.fa-2x {
+ font-size: 2em
+}
+
+.fa-3x {
+ font-size: 3em
+}
+
+.fa-4x {
+ font-size: 4em
+}
+
+.fa-5x {
+ font-size: 5em
+}
+
+.fa-fw {
+ width: 1.28571em;
+ text-align: center
+}
+
+.fa-ul {
+ padding-left: 0;
+ margin-left: 2.14286em;
+ list-style-type: none
+}
+
+.fa-ul>li {
+ position: relative
+}
+
+.fa-li {
+ position: absolute;
+ left: -2.14286em;
+ width: 2.14286em;
+ top: 0.14286em;
+ text-align: center
+}
+
+.fa-li.fa-lg {
+ left: -1.85714em
+}
+
+.fa-border {
+ padding: .2em .25em .15em;
+ border: solid 0.08em #eee;
+ border-radius: .1em
+}
+
+.pull-right {
+ float: right
+}
+
+.pull-left {
+ float: left
+}
+
+.fa.pull-left,
+.wy-menu-vertical li span.pull-left.toctree-expand,
+.wy-menu-vertical li.on a span.pull-left.toctree-expand,
+.wy-menu-vertical li.current>a span.pull-left.toctree-expand,
+.rst-content .pull-left.admonition-title,
+.rst-content h1 .pull-left.headerlink,
+.rst-content h2 .pull-left.headerlink,
+.rst-content h3 .pull-left.headerlink,
+.rst-content h4 .pull-left.headerlink,
+.rst-content h5 .pull-left.headerlink,
+.rst-content h6 .pull-left.headerlink,
+.rst-content dl dt .pull-left.headerlink,
+.rst-content p.caption .pull-left.headerlink,
+.rst-content tt.download span.pull-left:first-child,
+.rst-content code.download span.pull-left:first-child,
+.pull-left.icon {
+ margin-right: .3em
+}
+
+.fa.pull-right,
+.wy-menu-vertical li span.pull-right.toctree-expand,
+.wy-menu-vertical li.on a span.pull-right.toctree-expand,
+.wy-menu-vertical li.current>a span.pull-right.toctree-expand,
+.rst-content .pull-right.admonition-title,
+.rst-content h1 .pull-right.headerlink,
+.rst-content h2 .pull-right.headerlink,
+.rst-content h3 .pull-right.headerlink,
+.rst-content h4 .pull-right.headerlink,
+.rst-content h5 .pull-right.headerlink,
+.rst-content h6 .pull-right.headerlink,
+.rst-content dl dt .pull-right.headerlink,
+.rst-content p.caption .pull-right.headerlink,
+.rst-content tt.download span.pull-right:first-child,
+.rst-content code.download span.pull-right:first-child,
+.pull-right.icon {
+ margin-left: .3em
+}
+
+.fa-spin {
+ -webkit-animation: fa-spin 2s infinite linear;
+ animation: fa-spin 2s infinite linear
+}
+
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg)
+ }
+
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg)
+ }
+}
+
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg)
+ }
+
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg)
+ }
+}
+
+.fa-rotate-90 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+ -webkit-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ transform: rotate(90deg)
+}
+
+.fa-rotate-180 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+ -webkit-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ transform: rotate(180deg)
+}
+
+.fa-rotate-270 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+ -webkit-transform: rotate(270deg);
+ -ms-transform: rotate(270deg);
+ transform: rotate(270deg)
+}
+
+.fa-flip-horizontal {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
+ -webkit-transform: scale(-1, 1);
+ -ms-transform: scale(-1, 1);
+ transform: scale(-1, 1)
+}
+
+.fa-flip-vertical {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+ -webkit-transform: scale(1, -1);
+ -ms-transform: scale(1, -1);
+ transform: scale(1, -1)
+}
+
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+ filter: none
+}
+
+.fa-stack {
+ position: relative;
+ display: inline-block;
+ width: 2em;
+ height: 2em;
+ line-height: 2em;
+ vertical-align: middle
+}
+
+.fa-stack-1x,
+.fa-stack-2x {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ text-align: center
+}
+
+.fa-stack-1x {
+ line-height: inherit
+}
+
+.fa-stack-2x {
+ font-size: 2em
+}
+
+.fa-inverse {
+ color: #fff
+}
+
+.fa-glass:before {
+ content: ""
+}
+
+.fa-music:before {
+ content: ""
+}
+
+.fa-search:before,
+.icon-search:before {
+ content: ""
+}
+
+.fa-envelope-o:before {
+ content: ""
+}
+
+.fa-heart:before {
+ content: ""
+}
+
+.fa-star:before {
+ content: ""
+}
+
+.fa-star-o:before {
+ content: ""
+}
+
+.fa-user:before {
+ content: ""
+}
+
+.fa-film:before {
+ content: ""
+}
+
+.fa-th-large:before {
+ content: ""
+}
+
+.fa-th:before {
+ content: ""
+}
+
+.fa-th-list:before {
+ content: ""
+}
+
+.fa-check:before {
+ content: ""
+}
+
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+ content: ""
+}
+
+.fa-search-plus:before {
+ content: ""
+}
+
+.fa-search-minus:before {
+ content: ""
+}
+
+.fa-power-off:before {
+ content: ""
+}
+
+.fa-signal:before {
+ content: ""
+}
+
+.fa-gear:before,
+.fa-cog:before {
+ content: ""
+}
+
+.fa-trash-o:before {
+ content: ""
+}
+
+.fa-home:before,
+.icon-home:before {
+ content: ""
+}
+
+.fa-file-o:before {
+ content: ""
+}
+
+.fa-clock-o:before {
+ content: ""
+}
+
+.fa-road:before {
+ content: ""
+}
+
+.fa-download:before,
+.rst-content tt.download span:first-child:before,
+.rst-content code.download span:first-child:before {
+ content: ""
+}
+
+.fa-arrow-circle-o-down:before {
+ content: ""
+}
+
+.fa-arrow-circle-o-up:before {
+ content: ""
+}
+
+.fa-inbox:before {
+ content: ""
+}
+
+.fa-play-circle-o:before {
+ content: ""
+}
+
+.fa-rotate-right:before,
+.fa-repeat:before {
+ content: ""
+}
+
+.fa-refresh:before {
+ content: ""
+}
+
+.fa-list-alt:before {
+ content: ""
+}
+
+.fa-lock:before {
+ content: ""
+}
+
+.fa-flag:before {
+ content: ""
+}
+
+.fa-headphones:before {
+ content: ""
+}
+
+.fa-volume-off:before {
+ content: ""
+}
+
+.fa-volume-down:before {
+ content: ""
+}
+
+.fa-volume-up:before {
+ content: ""
+}
+
+.fa-qrcode:before {
+ content: ""
+}
+
+.fa-barcode:before {
+ content: ""
+}
+
+.fa-tag:before {
+ content: ""
+}
+
+.fa-tags:before {
+ content: ""
+}
+
+.fa-book:before,
+.icon-book:before {
+ content: ""
+}
+
+.fa-bookmark:before {
+ content: ""
+}
+
+.fa-print:before {
+ content: ""
+}
+
+.fa-camera:before {
+ content: ""
+}
+
+.fa-font:before {
+ content: ""
+}
+
+.fa-bold:before {
+ content: ""
+}
+
+.fa-italic:before {
+ content: ""
+}
+
+.fa-text-height:before {
+ content: ""
+}
+
+.fa-text-width:before {
+ content: ""
+}
+
+.fa-align-left:before {
+ content: ""
+}
+
+.fa-align-center:before {
+ content: ""
+}
+
+.fa-align-right:before {
+ content: ""
+}
+
+.fa-align-justify:before {
+ content: ""
+}
+
+.fa-list:before {
+ content: ""
+}
+
+.fa-dedent:before,
+.fa-outdent:before {
+ content: ""
+}
+
+.fa-indent:before {
+ content: ""
+}
+
+.fa-video-camera:before {
+ content: ""
+}
+
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+ content: ""
+}
+
+.fa-pencil:before {
+ content: ""
+}
+
+.fa-map-marker:before {
+ content: ""
+}
+
+.fa-adjust:before {
+ content: ""
+}
+
+.fa-tint:before {
+ content: ""
+}
+
+.fa-edit:before,
+.fa-pencil-square-o:before {
+ content: ""
+}
+
+.fa-share-square-o:before {
+ content: ""
+}
+
+.fa-check-square-o:before {
+ content: ""
+}
+
+.fa-arrows:before {
+ content: ""
+}
+
+.fa-step-backward:before {
+ content: ""
+}
+
+.fa-fast-backward:before {
+ content: ""
+}
+
+.fa-backward:before {
+ content: ""
+}
+
+.fa-play:before {
+ content: ""
+}
+
+.fa-pause:before {
+ content: ""
+}
+
+.fa-stop:before {
+ content: ""
+}
+
+.fa-forward:before {
+ content: ""
+}
+
+.fa-fast-forward:before {
+ content: ""
+}
+
+.fa-step-forward:before {
+ content: ""
+}
+
+.fa-eject:before {
+ content: ""
+}
+
+.fa-chevron-left:before {
+ content: ""
+}
+
+.fa-chevron-right:before {
+ content: ""
+}
+
+.fa-plus-circle:before {
+ content: ""
+}
+
+.fa-minus-circle:before {
+ content: ""
+}
+
+.fa-times-circle:before,
+.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before {
+ content: ""
+}
+
+.fa-check-circle:before,
+.wy-inline-validate.wy-inline-validate-success .wy-input-context:before {
+ content: ""
+}
+
+.fa-question-circle:before {
+ content: ""
+}
+
+.fa-info-circle:before {
+ content: ""
+}
+
+.fa-crosshairs:before {
+ content: ""
+}
+
+.fa-times-circle-o:before {
+ content: ""
+}
+
+.fa-check-circle-o:before {
+ content: ""
+}
+
+.fa-ban:before {
+ content: ""
+}
+
+.fa-arrow-left:before {
+ content: ""
+}
+
+.fa-arrow-right:before {
+ content: ""
+}
+
+.fa-arrow-up:before {
+ content: ""
+}
+
+.fa-arrow-down:before {
+ content: ""
+}
+
+.fa-mail-forward:before,
+.fa-share:before {
+ content: ""
+}
+
+.fa-expand:before {
+ content: ""
+}
+
+.fa-compress:before {
+ content: ""
+}
+
+.fa-plus:before {
+ content: ""
+}
+
+.fa-minus:before {
+ content: ""
+}
+
+.fa-asterisk:before {
+ content: ""
+}
+
+.fa-exclamation-circle:before,
+.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,
+.rst-content .admonition-title:before {
+ content: ""
+}
+
+.fa-gift:before {
+ content: ""
+}
+
+.fa-leaf:before {
+ content: ""
+}
+
+.fa-fire:before,
+.icon-fire:before {
+ content: ""
+}
+
+.fa-eye:before {
+ content: ""
+}
+
+.fa-eye-slash:before {
+ content: ""
+}
+
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+ content: ""
+}
+
+.fa-plane:before {
+ content: ""
+}
+
+.fa-calendar:before {
+ content: ""
+}
+
+.fa-random:before {
+ content: ""
+}
+
+.fa-comment:before {
+ content: ""
+}
+
+.fa-magnet:before {
+ content: ""
+}
+
+.fa-chevron-up:before {
+ content: ""
+}
+
+.fa-chevron-down:before {
+ content: ""
+}
+
+.fa-retweet:before {
+ content: ""
+}
+
+.fa-shopping-cart:before {
+ content: ""
+}
+
+.fa-folder:before {
+ content: ""
+}
+
+.fa-folder-open:before {
+ content: ""
+}
+
+.fa-arrows-v:before {
+ content: ""
+}
+
+.fa-arrows-h:before {
+ content: ""
+}
+
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+ content: ""
+}
+
+.fa-twitter-square:before {
+ content: ""
+}
+
+.fa-facebook-square:before {
+ content: ""
+}
+
+.fa-camera-retro:before {
+ content: ""
+}
+
+.fa-key:before {
+ content: ""
+}
+
+.fa-gears:before,
+.fa-cogs:before {
+ content: ""
+}
+
+.fa-comments:before {
+ content: ""
+}
+
+.fa-thumbs-o-up:before {
+ content: ""
+}
+
+.fa-thumbs-o-down:before {
+ content: ""
+}
+
+.fa-star-half:before {
+ content: ""
+}
+
+.fa-heart-o:before {
+ content: ""
+}
+
+.fa-sign-out:before {
+ content: ""
+}
+
+.fa-linkedin-square:before {
+ content: ""
+}
+
+.fa-thumb-tack:before {
+ content: ""
+}
+
+.fa-external-link:before {
+ content: ""
+}
+
+.fa-sign-in:before {
+ content: ""
+}
+
+.fa-trophy:before {
+ content: ""
+}
+
+.fa-github-square:before {
+ content: ""
+}
+
+.fa-upload:before {
+ content: ""
+}
+
+.fa-lemon-o:before {
+ content: ""
+}
+
+.fa-phone:before {
+ content: ""
+}
+
+.fa-square-o:before {
+ content: ""
+}
+
+.fa-bookmark-o:before {
+ content: ""
+}
+
+.fa-phone-square:before {
+ content: ""
+}
+
+.fa-twitter:before {
+ content: ""
+}
+
+.fa-facebook:before {
+ content: ""
+}
+
+.fa-github:before,
+.icon-github:before {
+ content: ""
+}
+
+.fa-unlock:before {
+ content: ""
+}
+
+.fa-credit-card:before {
+ content: ""
+}
+
+.fa-rss:before {
+ content: ""
+}
+
+.fa-hdd-o:before {
+ content: ""
+}
+
+.fa-bullhorn:before {
+ content: ""
+}
+
+.fa-bell:before {
+ content: ""
+}
+
+.fa-certificate:before {
+ content: ""
+}
+
+.fa-hand-o-right:before {
+ content: ""
+}
+
+.fa-hand-o-left:before {
+ content: ""
+}
+
+.fa-hand-o-up:before {
+ content: ""
+}
+
+.fa-hand-o-down:before {
+ content: ""
+}
+
+.fa-arrow-circle-left:before,
+.icon-circle-arrow-left:before {
+ content: ""
+}
+
+.fa-arrow-circle-right:before,
+.icon-circle-arrow-right:before {
+ content: ""
+}
+
+.fa-arrow-circle-up:before {
+ content: ""
+}
+
+.fa-arrow-circle-down:before {
+ content: ""
+}
+
+.fa-globe:before {
+ content: ""
+}
+
+.fa-wrench:before {
+ content: ""
+}
+
+.fa-tasks:before {
+ content: ""
+}
+
+.fa-filter:before {
+ content: ""
+}
+
+.fa-briefcase:before {
+ content: ""
+}
+
+.fa-arrows-alt:before {
+ content: ""
+}
+
+.fa-group:before,
+.fa-users:before {
+ content: ""
+}
+
+.fa-chain:before,
+.fa-link:before,
+.icon-link:before {
+ content: ""
+}
+
+.fa-cloud:before {
+ content: ""
+}
+
+.fa-flask:before {
+ content: ""
+}
+
+.fa-cut:before,
+.fa-scissors:before {
+ content: ""
+}
+
+.fa-copy:before,
+.fa-files-o:before {
+ content: ""
+}
+
+.fa-paperclip:before {
+ content: ""
+}
+
+.fa-save:before,
+.fa-floppy-o:before {
+ content: ""
+}
+
+.fa-square:before {
+ content: ""
+}
+
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+ content: ""
+}
+
+.fa-list-ul:before {
+ content: ""
+}
+
+.fa-list-ol:before {
+ content: ""
+}
+
+.fa-strikethrough:before {
+ content: ""
+}
+
+.fa-underline:before {
+ content: ""
+}
+
+.fa-table:before {
+ content: ""
+}
+
+.fa-magic:before {
+ content: ""
+}
+
+.fa-truck:before {
+ content: ""
+}
+
+.fa-pinterest:before {
+ content: ""
+}
+
+.fa-pinterest-square:before {
+ content: ""
+}
+
+.fa-google-plus-square:before {
+ content: ""
+}
+
+.fa-google-plus:before {
+ content: ""
+}
+
+.fa-money:before {
+ content: ""
+}
+
+.fa-caret-down:before,
+.wy-dropdown .caret:before,
+.icon-caret-down:before {
+ content: ""
+}
+
+.fa-caret-up:before {
+ content: ""
+}
+
+.fa-caret-left:before {
+ content: ""
+}
+
+.fa-caret-right:before {
+ content: ""
+}
+
+.fa-columns:before {
+ content: ""
+}
+
+.fa-unsorted:before,
+.fa-sort:before {
+ content: ""
+}
+
+.fa-sort-down:before,
+.fa-sort-desc:before {
+ content: ""
+}
+
+.fa-sort-up:before,
+.fa-sort-asc:before {
+ content: ""
+}
+
+.fa-envelope:before {
+ content: ""
+}
+
+.fa-linkedin:before {
+ content: ""
+}
+
+.fa-rotate-left:before,
+.fa-undo:before {
+ content: ""
+}
+
+.fa-legal:before,
+.fa-gavel:before {
+ content: ""
+}
+
+.fa-dashboard:before,
+.fa-tachometer:before {
+ content: ""
+}
+
+.fa-comment-o:before {
+ content: ""
+}
+
+.fa-comments-o:before {
+ content: ""
+}
+
+.fa-flash:before,
+.fa-bolt:before {
+ content: ""
+}
+
+.fa-sitemap:before {
+ content: ""
+}
+
+.fa-umbrella:before {
+ content: ""
+}
+
+.fa-paste:before,
+.fa-clipboard:before {
+ content: ""
+}
+
+.fa-lightbulb-o:before {
+ content: ""
+}
+
+.fa-exchange:before {
+ content: ""
+}
+
+.fa-cloud-download:before {
+ content: ""
+}
+
+.fa-cloud-upload:before {
+ content: ""
+}
+
+.fa-user-md:before {
+ content: ""
+}
+
+.fa-stethoscope:before {
+ content: ""
+}
+
+.fa-suitcase:before {
+ content: ""
+}
+
+.fa-bell-o:before {
+ content: ""
+}
+
+.fa-coffee:before {
+ content: ""
+}
+
+.fa-cutlery:before {
+ content: ""
+}
+
+.fa-file-text-o:before {
+ content: ""
+}
+
+.fa-building-o:before {
+ content: ""
+}
+
+.fa-hospital-o:before {
+ content: ""
+}
+
+.fa-ambulance:before {
+ content: ""
+}
+
+.fa-medkit:before {
+ content: ""
+}
+
+.fa-fighter-jet:before {
+ content: ""
+}
+
+.fa-beer:before {
+ content: ""
+}
+
+.fa-h-square:before {
+ content: ""
+}
+
+.fa-plus-square:before {
+ content: ""
+}
+
+.fa-angle-double-left:before {
+ content: ""
+}
+
+.fa-angle-double-right:before {
+ content: ""
+}
+
+.fa-angle-double-up:before {
+ content: ""
+}
+
+.fa-angle-double-down:before {
+ content: ""
+}
+
+.fa-angle-left:before {
+ content: ""
+}
+
+.fa-angle-right:before {
+ content: ""
+}
+
+.fa-angle-up:before {
+ content: ""
+}
+
+.fa-angle-down:before {
+ content: ""
+}
+
+.fa-desktop:before {
+ content: ""
+}
+
+.fa-laptop:before {
+ content: ""
+}
+
+.fa-tablet:before {
+ content: ""
+}
+
+.fa-mobile-phone:before,
+.fa-mobile:before {
+ content: ""
+}
+
+.fa-circle-o:before {
+ content: ""
+}
+
+.fa-quote-left:before {
+ content: ""
+}
+
+.fa-quote-right:before {
+ content: ""
+}
+
+.fa-spinner:before {
+ content: ""
+}
+
+.fa-circle:before {
+ content: ""
+}
+
+.fa-mail-reply:before,
+.fa-reply:before {
+ content: ""
+}
+
+.fa-github-alt:before {
+ content: ""
+}
+
+.fa-folder-o:before {
+ content: ""
+}
+
+.fa-folder-open-o:before {
+ content: ""
+}
+
+.fa-smile-o:before {
+ content: ""
+}
+
+.fa-frown-o:before {
+ content: ""
+}
+
+.fa-meh-o:before {
+ content: ""
+}
+
+.fa-gamepad:before {
+ content: ""
+}
+
+.fa-keyboard-o:before {
+ content: ""
+}
+
+.fa-flag-o:before {
+ content: ""
+}
+
+.fa-flag-checkered:before {
+ content: ""
+}
+
+.fa-terminal:before {
+ content: ""
+}
+
+.fa-code:before {
+ content: ""
+}
+
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+ content: ""
+}
+
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+ content: ""
+}
+
+.fa-location-arrow:before {
+ content: ""
+}
+
+.fa-crop:before {
+ content: ""
+}
+
+.fa-code-fork:before {
+ content: ""
+}
+
+.fa-unlink:before,
+.fa-chain-broken:before {
+ content: ""
+}
+
+.fa-question:before {
+ content: ""
+}
+
+.fa-info:before {
+ content: ""
+}
+
+.fa-exclamation:before {
+ content: ""
+}
+
+.fa-superscript:before {
+ content: ""
+}
+
+.fa-subscript:before {
+ content: ""
+}
+
+.fa-eraser:before {
+ content: ""
+}
+
+.fa-puzzle-piece:before {
+ content: ""
+}
+
+.fa-microphone:before {
+ content: ""
+}
+
+.fa-microphone-slash:before {
+ content: ""
+}
+
+.fa-shield:before {
+ content: ""
+}
+
+.fa-calendar-o:before {
+ content: ""
+}
+
+.fa-fire-extinguisher:before {
+ content: ""
+}
+
+.fa-rocket:before {
+ content: ""
+}
+
+.fa-maxcdn:before {
+ content: ""
+}
+
+.fa-chevron-circle-left:before {
+ content: ""
+}
+
+.fa-chevron-circle-right:before {
+ content: ""
+}
+
+.fa-chevron-circle-up:before {
+ content: ""
+}
+
+.fa-chevron-circle-down:before {
+ content: ""
+}
+
+.fa-html5:before {
+ content: ""
+}
+
+.fa-css3:before {
+ content: ""
+}
+
+.fa-anchor:before {
+ content: ""
+}
+
+.fa-unlock-alt:before {
+ content: ""
+}
+
+.fa-bullseye:before {
+ content: ""
+}
+
+.fa-ellipsis-h:before {
+ content: ""
+}
+
+.fa-ellipsis-v:before {
+ content: ""
+}
+
+.fa-rss-square:before {
+ content: ""
+}
+
+.fa-play-circle:before {
+ content: ""
+}
+
+.fa-ticket:before {
+ content: ""
+}
+
+.fa-minus-square:before {
+ content: ""
+}
+
+.fa-minus-square-o:before,
+.wy-menu-vertical li.on a span.toctree-expand:before,
+.wy-menu-vertical li.current>a span.toctree-expand:before {
+ content: ""
+}
+
+.fa-level-up:before {
+ content: ""
+}
+
+.fa-level-down:before {
+ content: ""
+}
+
+.fa-check-square:before {
+ content: ""
+}
+
+.fa-pencil-square:before {
+ content: ""
+}
+
+.fa-external-link-square:before {
+ content: ""
+}
+
+.fa-share-square:before {
+ content: ""
+}
+
+.fa-compass:before {
+ content: ""
+}
+
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+ content: ""
+}
+
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+ content: ""
+}
+
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+ content: ""
+}
+
+.fa-euro:before,
+.fa-eur:before {
+ content: ""
+}
+
+.fa-gbp:before {
+ content: ""
+}
+
+.fa-dollar:before,
+.fa-usd:before {
+ content: ""
+}
+
+.fa-rupee:before,
+.fa-inr:before {
+ content: ""
+}
+
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+ content: ""
+}
+
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+ content: ""
+}
+
+.fa-won:before,
+.fa-krw:before {
+ content: ""
+}
+
+.fa-bitcoin:before,
+.fa-btc:before {
+ content: ""
+}
+
+.fa-file:before {
+ content: ""
+}
+
+.fa-file-text:before {
+ content: ""
+}
+
+.fa-sort-alpha-asc:before {
+ content: ""
+}
+
+.fa-sort-alpha-desc:before {
+ content: ""
+}
+
+.fa-sort-amount-asc:before {
+ content: ""
+}
+
+.fa-sort-amount-desc:before {
+ content: ""
+}
+
+.fa-sort-numeric-asc:before {
+ content: ""
+}
+
+.fa-sort-numeric-desc:before {
+ content: ""
+}
+
+.fa-thumbs-up:before {
+ content: ""
+}
+
+.fa-thumbs-down:before {
+ content: ""
+}
+
+.fa-youtube-square:before {
+ content: ""
+}
+
+.fa-youtube:before {
+ content: ""
+}
+
+.fa-xing:before {
+ content: ""
+}
+
+.fa-xing-square:before {
+ content: ""
+}
+
+.fa-youtube-play:before {
+ content: ""
+}
+
+.fa-dropbox:before {
+ content: ""
+}
+
+.fa-stack-overflow:before {
+ content: ""
+}
+
+.fa-instagram:before {
+ content: ""
+}
+
+.fa-flickr:before {
+ content: ""
+}
+
+.fa-adn:before {
+ content: ""
+}
+
+.fa-bitbucket:before,
+.icon-bitbucket:before {
+ content: ""
+}
+
+.fa-bitbucket-square:before {
+ content: ""
+}
+
+.fa-tumblr:before {
+ content: ""
+}
+
+.fa-tumblr-square:before {
+ content: ""
+}
+
+.fa-long-arrow-down:before {
+ content: ""
+}
+
+.fa-long-arrow-up:before {
+ content: ""
+}
+
+.fa-long-arrow-left:before {
+ content: ""
+}
+
+.fa-long-arrow-right:before {
+ content: ""
+}
+
+.fa-apple:before {
+ content: ""
+}
+
+.fa-windows:before {
+ content: ""
+}
+
+.fa-android:before {
+ content: ""
+}
+
+.fa-linux:before {
+ content: ""
+}
+
+.fa-dribbble:before {
+ content: ""
+}
+
+.fa-skype:before {
+ content: ""
+}
+
+.fa-foursquare:before {
+ content: ""
+}
+
+.fa-trello:before {
+ content: ""
+}
+
+.fa-female:before {
+ content: ""
+}
+
+.fa-male:before {
+ content: ""
+}
+
+.fa-gittip:before {
+ content: ""
+}
+
+.fa-sun-o:before {
+ content: ""
+}
+
+.fa-moon-o:before {
+ content: ""
+}
+
+.fa-archive:before {
+ content: ""
+}
+
+.fa-bug:before {
+ content: ""
+}
+
+.fa-vk:before {
+ content: ""
+}
+
+.fa-weibo:before {
+ content: ""
+}
+
+.fa-renren:before {
+ content: ""
+}
+
+.fa-pagelines:before {
+ content: ""
+}
+
+.fa-stack-exchange:before {
+ content: ""
+}
+
+.fa-arrow-circle-o-right:before {
+ content: ""
+}
+
+.fa-arrow-circle-o-left:before {
+ content: ""
+}
+
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+ content: ""
+}
+
+.fa-dot-circle-o:before {
+ content: ""
+}
+
+.fa-wheelchair:before {
+ content: ""
+}
+
+.fa-vimeo-square:before {
+ content: ""
+}
+
+.fa-turkish-lira:before,
+.fa-try:before {
+ content: ""
+}
+
+.fa-plus-square-o:before,
+.wy-menu-vertical li span.toctree-expand:before {
+ content: ""
+}
+
+.fa-space-shuttle:before {
+ content: ""
+}
+
+.fa-slack:before {
+ content: ""
+}
+
+.fa-envelope-square:before {
+ content: ""
+}
+
+.fa-wordpress:before {
+ content: ""
+}
+
+.fa-openid:before {
+ content: ""
+}
+
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+ content: ""
+}
+
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+ content: ""
+}
+
+.fa-yahoo:before {
+ content: ""
+}
+
+.fa-google:before {
+ content: ""
+}
+
+.fa-reddit:before {
+ content: ""
+}
+
+.fa-reddit-square:before {
+ content: ""
+}
+
+.fa-stumbleupon-circle:before {
+ content: ""
+}
+
+.fa-stumbleupon:before {
+ content: ""
+}
+
+.fa-delicious:before {
+ content: ""
+}
+
+.fa-digg:before {
+ content: ""
+}
+
+.fa-pied-piper:before {
+ content: ""
+}
+
+.fa-pied-piper-alt:before {
+ content: ""
+}
+
+.fa-drupal:before {
+ content: ""
+}
+
+.fa-joomla:before {
+ content: ""
+}
+
+.fa-language:before {
+ content: ""
+}
+
+.fa-fax:before {
+ content: ""
+}
+
+.fa-building:before {
+ content: ""
+}
+
+.fa-child:before {
+ content: ""
+}
+
+.fa-paw:before {
+ content: ""
+}
+
+.fa-spoon:before {
+ content: ""
+}
+
+.fa-cube:before {
+ content: ""
+}
+
+.fa-cubes:before {
+ content: ""
+}
+
+.fa-behance:before {
+ content: ""
+}
+
+.fa-behance-square:before {
+ content: ""
+}
+
+.fa-steam:before {
+ content: ""
+}
+
+.fa-steam-square:before {
+ content: ""
+}
+
+.fa-recycle:before {
+ content: ""
+}
+
+.fa-automobile:before,
+.fa-car:before {
+ content: ""
+}
+
+.fa-cab:before,
+.fa-taxi:before {
+ content: ""
+}
+
+.fa-tree:before {
+ content: ""
+}
+
+.fa-spotify:before {
+ content: ""
+}
+
+.fa-deviantart:before {
+ content: ""
+}
+
+.fa-soundcloud:before {
+ content: ""
+}
+
+.fa-database:before {
+ content: ""
+}
+
+.fa-file-pdf-o:before {
+ content: ""
+}
+
+.fa-file-word-o:before {
+ content: ""
+}
+
+.fa-file-excel-o:before {
+ content: ""
+}
+
+.fa-file-powerpoint-o:before {
+ content: ""
+}
+
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+ content: ""
+}
+
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+ content: ""
+}
+
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+ content: ""
+}
+
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+ content: ""
+}
+
+.fa-file-code-o:before {
+ content: ""
+}
+
+.fa-vine:before {
+ content: ""
+}
+
+.fa-codepen:before {
+ content: ""
+}
+
+.fa-jsfiddle:before {
+ content: ""
+}
+
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+ content: ""
+}
+
+.fa-circle-o-notch:before {
+ content: ""
+}
+
+.fa-ra:before,
+.fa-rebel:before {
+ content: ""
+}
+
+.fa-ge:before,
+.fa-empire:before {
+ content: ""
+}
+
+.fa-git-square:before {
+ content: ""
+}
+
+.fa-git:before {
+ content: ""
+}
+
+.fa-hacker-news:before {
+ content: ""
+}
+
+.fa-tencent-weibo:before {
+ content: ""
+}
+
+.fa-qq:before {
+ content: ""
+}
+
+.fa-wechat:before,
+.fa-weixin:before {
+ content: ""
+}
+
+.fa-send:before,
+.fa-paper-plane:before {
+ content: ""
+}
+
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+ content: ""
+}
+
+.fa-history:before {
+ content: ""
+}
+
+.fa-circle-thin:before {
+ content: ""
+}
+
+.fa-header:before {
+ content: ""
+}
+
+.fa-paragraph:before {
+ content: ""
+}
+
+.fa-sliders:before {
+ content: ""
+}
+
+.fa-share-alt:before {
+ content: ""
+}
+
+.fa-share-alt-square:before {
+ content: ""
+}
+
+.fa-bomb:before {
+ content: ""
+}
+
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+ content: ""
+}
+
+.fa-tty:before {
+ content: ""
+}
+
+.fa-binoculars:before {
+ content: ""
+}
+
+.fa-plug:before {
+ content: ""
+}
+
+.fa-slideshare:before {
+ content: ""
+}
+
+.fa-twitch:before {
+ content: ""
+}
+
+.fa-yelp:before {
+ content: ""
+}
+
+.fa-newspaper-o:before {
+ content: ""
+}
+
+.fa-wifi:before {
+ content: ""
+}
+
+.fa-calculator:before {
+ content: ""
+}
+
+.fa-paypal:before {
+ content: ""
+}
+
+.fa-google-wallet:before {
+ content: ""
+}
+
+.fa-cc-visa:before {
+ content: ""
+}
+
+.fa-cc-mastercard:before {
+ content: ""
+}
+
+.fa-cc-discover:before {
+ content: ""
+}
+
+.fa-cc-amex:before {
+ content: ""
+}
+
+.fa-cc-paypal:before {
+ content: ""
+}
+
+.fa-cc-stripe:before {
+ content: ""
+}
+
+.fa-bell-slash:before {
+ content: ""
+}
+
+.fa-bell-slash-o:before {
+ content: ""
+}
+
+.fa-trash:before {
+ content: ""
+}
+
+.fa-copyright:before {
+ content: ""
+}
+
+.fa-at:before {
+ content: ""
+}
+
+.fa-eyedropper:before {
+ content: ""
+}
+
+.fa-paint-brush:before {
+ content: ""
+}
+
+.fa-birthday-cake:before {
+ content: ""
+}
+
+.fa-area-chart:before {
+ content: ""
+}
+
+.fa-pie-chart:before {
+ content: ""
+}
+
+.fa-line-chart:before {
+ content: ""
+}
+
+.fa-lastfm:before {
+ content: ""
+}
+
+.fa-lastfm-square:before {
+ content: ""
+}
+
+.fa-toggle-off:before {
+ content: ""
+}
+
+.fa-toggle-on:before {
+ content: ""
+}
+
+.fa-bicycle:before {
+ content: ""
+}
+
+.fa-bus:before {
+ content: ""
+}
+
+.fa-ioxhost:before {
+ content: ""
+}
+
+.fa-angellist:before {
+ content: ""
+}
+
+.fa-cc:before {
+ content: ""
+}
+
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+ content: ""
+}
+
+.fa-meanpath:before {
+ content: ""
+}
+
+.fa,
+.wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.current>a span.toctree-expand,
+.rst-content .admonition-title,
+.rst-content h1 .headerlink,
+.rst-content h2 .headerlink,
+.rst-content h3 .headerlink,
+.rst-content h4 .headerlink,
+.rst-content h5 .headerlink,
+.rst-content h6 .headerlink,
+.rst-content dl dt .headerlink,
+.rst-content p.caption .headerlink,
+.rst-content tt.download span:first-child,
+.rst-content code.download span:first-child,
+.icon,
+.wy-dropdown .caret,
+.wy-inline-validate.wy-inline-validate-success .wy-input-context,
+.wy-inline-validate.wy-inline-validate-danger .wy-input-context,
+.wy-inline-validate.wy-inline-validate-warning .wy-input-context,
+.wy-inline-validate.wy-inline-validate-info .wy-input-context {
+ font-family: inherit
+}
+
+.fa:before,
+.wy-menu-vertical li span.toctree-expand:before,
+.wy-menu-vertical li.on a span.toctree-expand:before,
+.wy-menu-vertical li.current>a span.toctree-expand:before,
+.rst-content .admonition-title:before,
+.rst-content h1 .headerlink:before,
+.rst-content h2 .headerlink:before,
+.rst-content h3 .headerlink:before,
+.rst-content h4 .headerlink:before,
+.rst-content h5 .headerlink:before,
+.rst-content h6 .headerlink:before,
+.rst-content dl dt .headerlink:before,
+.rst-content p.caption .headerlink:before,
+.rst-content tt.download span:first-child:before,
+.rst-content code.download span:first-child:before,
+.icon:before,
+.wy-dropdown .caret:before,
+.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,
+.wy-inline-validate.wy-inline-validate-info .wy-input-context:before {
+ font-family: "FontAwesome";
+ display: inline-block;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ text-decoration: inherit
+}
+
+a .fa,
+a .wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li a span.toctree-expand,
+.wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.current>a span.toctree-expand,
+a .rst-content .admonition-title,
+.rst-content a .admonition-title,
+a .rst-content h1 .headerlink,
+.rst-content h1 a .headerlink,
+a .rst-content h2 .headerlink,
+.rst-content h2 a .headerlink,
+a .rst-content h3 .headerlink,
+.rst-content h3 a .headerlink,
+a .rst-content h4 .headerlink,
+.rst-content h4 a .headerlink,
+a .rst-content h5 .headerlink,
+.rst-content h5 a .headerlink,
+a .rst-content h6 .headerlink,
+.rst-content h6 a .headerlink,
+a .rst-content dl dt .headerlink,
+.rst-content dl dt a .headerlink,
+a .rst-content p.caption .headerlink,
+.rst-content p.caption a .headerlink,
+a .rst-content tt.download span:first-child,
+.rst-content tt.download a span:first-child,
+a .rst-content code.download span:first-child,
+.rst-content code.download a span:first-child,
+a .icon {
+ display: inline-block;
+ text-decoration: inherit
+}
+
+.btn .fa,
+.btn .wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li .btn span.toctree-expand,
+.btn .wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.on a .btn span.toctree-expand,
+.btn .wy-menu-vertical li.current>a span.toctree-expand,
+.wy-menu-vertical li.current>a .btn span.toctree-expand,
+.btn .rst-content .admonition-title,
+.rst-content .btn .admonition-title,
+.btn .rst-content h1 .headerlink,
+.rst-content h1 .btn .headerlink,
+.btn .rst-content h2 .headerlink,
+.rst-content h2 .btn .headerlink,
+.btn .rst-content h3 .headerlink,
+.rst-content h3 .btn .headerlink,
+.btn .rst-content h4 .headerlink,
+.rst-content h4 .btn .headerlink,
+.btn .rst-content h5 .headerlink,
+.rst-content h5 .btn .headerlink,
+.btn .rst-content h6 .headerlink,
+.rst-content h6 .btn .headerlink,
+.btn .rst-content dl dt .headerlink,
+.rst-content dl dt .btn .headerlink,
+.btn .rst-content p.caption .headerlink,
+.rst-content p.caption .btn .headerlink,
+.btn .rst-content tt.download span:first-child,
+.rst-content tt.download .btn span:first-child,
+.btn .rst-content code.download span:first-child,
+.rst-content code.download .btn span:first-child,
+.btn .icon,
+.nav .fa,
+.nav .wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li .nav span.toctree-expand,
+.nav .wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.on a .nav span.toctree-expand,
+.nav .wy-menu-vertical li.current>a span.toctree-expand,
+.wy-menu-vertical li.current>a .nav span.toctree-expand,
+.nav .rst-content .admonition-title,
+.rst-content .nav .admonition-title,
+.nav .rst-content h1 .headerlink,
+.rst-content h1 .nav .headerlink,
+.nav .rst-content h2 .headerlink,
+.rst-content h2 .nav .headerlink,
+.nav .rst-content h3 .headerlink,
+.rst-content h3 .nav .headerlink,
+.nav .rst-content h4 .headerlink,
+.rst-content h4 .nav .headerlink,
+.nav .rst-content h5 .headerlink,
+.rst-content h5 .nav .headerlink,
+.nav .rst-content h6 .headerlink,
+.rst-content h6 .nav .headerlink,
+.nav .rst-content dl dt .headerlink,
+.rst-content dl dt .nav .headerlink,
+.nav .rst-content p.caption .headerlink,
+.rst-content p.caption .nav .headerlink,
+.nav .rst-content tt.download span:first-child,
+.rst-content tt.download .nav span:first-child,
+.nav .rst-content code.download span:first-child,
+.rst-content code.download .nav span:first-child,
+.nav .icon {
+ display: inline
+}
+
+.btn .fa.fa-large,
+.btn .wy-menu-vertical li span.fa-large.toctree-expand,
+.wy-menu-vertical li .btn span.fa-large.toctree-expand,
+.btn .rst-content .fa-large.admonition-title,
+.rst-content .btn .fa-large.admonition-title,
+.btn .rst-content h1 .fa-large.headerlink,
+.rst-content h1 .btn .fa-large.headerlink,
+.btn .rst-content h2 .fa-large.headerlink,
+.rst-content h2 .btn .fa-large.headerlink,
+.btn .rst-content h3 .fa-large.headerlink,
+.rst-content h3 .btn .fa-large.headerlink,
+.btn .rst-content h4 .fa-large.headerlink,
+.rst-content h4 .btn .fa-large.headerlink,
+.btn .rst-content h5 .fa-large.headerlink,
+.rst-content h5 .btn .fa-large.headerlink,
+.btn .rst-content h6 .fa-large.headerlink,
+.rst-content h6 .btn .fa-large.headerlink,
+.btn .rst-content dl dt .fa-large.headerlink,
+.rst-content dl dt .btn .fa-large.headerlink,
+.btn .rst-content p.caption .fa-large.headerlink,
+.rst-content p.caption .btn .fa-large.headerlink,
+.btn .rst-content tt.download span.fa-large:first-child,
+.rst-content tt.download .btn span.fa-large:first-child,
+.btn .rst-content code.download span.fa-large:first-child,
+.rst-content code.download .btn span.fa-large:first-child,
+.btn .fa-large.icon,
+.nav .fa.fa-large,
+.nav .wy-menu-vertical li span.fa-large.toctree-expand,
+.wy-menu-vertical li .nav span.fa-large.toctree-expand,
+.nav .rst-content .fa-large.admonition-title,
+.rst-content .nav .fa-large.admonition-title,
+.nav .rst-content h1 .fa-large.headerlink,
+.rst-content h1 .nav .fa-large.headerlink,
+.nav .rst-content h2 .fa-large.headerlink,
+.rst-content h2 .nav .fa-large.headerlink,
+.nav .rst-content h3 .fa-large.headerlink,
+.rst-content h3 .nav .fa-large.headerlink,
+.nav .rst-content h4 .fa-large.headerlink,
+.rst-content h4 .nav .fa-large.headerlink,
+.nav .rst-content h5 .fa-large.headerlink,
+.rst-content h5 .nav .fa-large.headerlink,
+.nav .rst-content h6 .fa-large.headerlink,
+.rst-content h6 .nav .fa-large.headerlink,
+.nav .rst-content dl dt .fa-large.headerlink,
+.rst-content dl dt .nav .fa-large.headerlink,
+.nav .rst-content p.caption .fa-large.headerlink,
+.rst-content p.caption .nav .fa-large.headerlink,
+.nav .rst-content tt.download span.fa-large:first-child,
+.rst-content tt.download .nav span.fa-large:first-child,
+.nav .rst-content code.download span.fa-large:first-child,
+.rst-content code.download .nav span.fa-large:first-child,
+.nav .fa-large.icon {
+ line-height: 0.9em
+}
+
+.btn .fa.fa-spin,
+.btn .wy-menu-vertical li span.fa-spin.toctree-expand,
+.wy-menu-vertical li .btn span.fa-spin.toctree-expand,
+.btn .rst-content .fa-spin.admonition-title,
+.rst-content .btn .fa-spin.admonition-title,
+.btn .rst-content h1 .fa-spin.headerlink,
+.rst-content h1 .btn .fa-spin.headerlink,
+.btn .rst-content h2 .fa-spin.headerlink,
+.rst-content h2 .btn .fa-spin.headerlink,
+.btn .rst-content h3 .fa-spin.headerlink,
+.rst-content h3 .btn .fa-spin.headerlink,
+.btn .rst-content h4 .fa-spin.headerlink,
+.rst-content h4 .btn .fa-spin.headerlink,
+.btn .rst-content h5 .fa-spin.headerlink,
+.rst-content h5 .btn .fa-spin.headerlink,
+.btn .rst-content h6 .fa-spin.headerlink,
+.rst-content h6 .btn .fa-spin.headerlink,
+.btn .rst-content dl dt .fa-spin.headerlink,
+.rst-content dl dt .btn .fa-spin.headerlink,
+.btn .rst-content p.caption .fa-spin.headerlink,
+.rst-content p.caption .btn .fa-spin.headerlink,
+.btn .rst-content tt.download span.fa-spin:first-child,
+.rst-content tt.download .btn span.fa-spin:first-child,
+.btn .rst-content code.download span.fa-spin:first-child,
+.rst-content code.download .btn span.fa-spin:first-child,
+.btn .fa-spin.icon,
+.nav .fa.fa-spin,
+.nav .wy-menu-vertical li span.fa-spin.toctree-expand,
+.wy-menu-vertical li .nav span.fa-spin.toctree-expand,
+.nav .rst-content .fa-spin.admonition-title,
+.rst-content .nav .fa-spin.admonition-title,
+.nav .rst-content h1 .fa-spin.headerlink,
+.rst-content h1 .nav .fa-spin.headerlink,
+.nav .rst-content h2 .fa-spin.headerlink,
+.rst-content h2 .nav .fa-spin.headerlink,
+.nav .rst-content h3 .fa-spin.headerlink,
+.rst-content h3 .nav .fa-spin.headerlink,
+.nav .rst-content h4 .fa-spin.headerlink,
+.rst-content h4 .nav .fa-spin.headerlink,
+.nav .rst-content h5 .fa-spin.headerlink,
+.rst-content h5 .nav .fa-spin.headerlink,
+.nav .rst-content h6 .fa-spin.headerlink,
+.rst-content h6 .nav .fa-spin.headerlink,
+.nav .rst-content dl dt .fa-spin.headerlink,
+.rst-content dl dt .nav .fa-spin.headerlink,
+.nav .rst-content p.caption .fa-spin.headerlink,
+.rst-content p.caption .nav .fa-spin.headerlink,
+.nav .rst-content tt.download span.fa-spin:first-child,
+.rst-content tt.download .nav span.fa-spin:first-child,
+.nav .rst-content code.download span.fa-spin:first-child,
+.rst-content code.download .nav span.fa-spin:first-child,
+.nav .fa-spin.icon {
+ display: inline-block
+}
+
+.btn.fa:before,
+.wy-menu-vertical li span.btn.toctree-expand:before,
+.rst-content .btn.admonition-title:before,
+.rst-content h1 .btn.headerlink:before,
+.rst-content h2 .btn.headerlink:before,
+.rst-content h3 .btn.headerlink:before,
+.rst-content h4 .btn.headerlink:before,
+.rst-content h5 .btn.headerlink:before,
+.rst-content h6 .btn.headerlink:before,
+.rst-content dl dt .btn.headerlink:before,
+.rst-content p.caption .btn.headerlink:before,
+.rst-content tt.download span.btn:first-child:before,
+.rst-content code.download span.btn:first-child:before,
+.btn.icon:before {
+ opacity: 0.5;
+ -webkit-transition: opacity 0.05s ease-in;
+ -moz-transition: opacity 0.05s ease-in;
+ transition: opacity 0.05s ease-in
+}
+
+.btn.fa:hover:before,
+.wy-menu-vertical li span.btn.toctree-expand:hover:before,
+.rst-content .btn.admonition-title:hover:before,
+.rst-content h1 .btn.headerlink:hover:before,
+.rst-content h2 .btn.headerlink:hover:before,
+.rst-content h3 .btn.headerlink:hover:before,
+.rst-content h4 .btn.headerlink:hover:before,
+.rst-content h5 .btn.headerlink:hover:before,
+.rst-content h6 .btn.headerlink:hover:before,
+.rst-content dl dt .btn.headerlink:hover:before,
+.rst-content p.caption .btn.headerlink:hover:before,
+.rst-content tt.download span.btn:first-child:hover:before,
+.rst-content code.download span.btn:first-child:hover:before,
+.btn.icon:hover:before {
+ opacity: 1
+}
+
+.btn-mini .fa:before,
+.btn-mini .wy-menu-vertical li span.toctree-expand:before,
+.wy-menu-vertical li .btn-mini span.toctree-expand:before,
+.btn-mini .rst-content .admonition-title:before,
+.rst-content .btn-mini .admonition-title:before,
+.btn-mini .rst-content h1 .headerlink:before,
+.rst-content h1 .btn-mini .headerlink:before,
+.btn-mini .rst-content h2 .headerlink:before,
+.rst-content h2 .btn-mini .headerlink:before,
+.btn-mini .rst-content h3 .headerlink:before,
+.rst-content h3 .btn-mini .headerlink:before,
+.btn-mini .rst-content h4 .headerlink:before,
+.rst-content h4 .btn-mini .headerlink:before,
+.btn-mini .rst-content h5 .headerlink:before,
+.rst-content h5 .btn-mini .headerlink:before,
+.btn-mini .rst-content h6 .headerlink:before,
+.rst-content h6 .btn-mini .headerlink:before,
+.btn-mini .rst-content dl dt .headerlink:before,
+.rst-content dl dt .btn-mini .headerlink:before,
+.btn-mini .rst-content p.caption .headerlink:before,
+.rst-content p.caption .btn-mini .headerlink:before,
+.btn-mini .rst-content tt.download span:first-child:before,
+.rst-content tt.download .btn-mini span:first-child:before,
+.btn-mini .rst-content code.download span:first-child:before,
+.rst-content code.download .btn-mini span:first-child:before,
+.btn-mini .icon:before {
+ font-size: 14px;
+ vertical-align: -15%
+}
+
+.wy-alert,
+.rst-content .note,
+.rst-content .attention,
+.rst-content .caution,
+.rst-content .danger,
+.rst-content .error,
+.rst-content .hint,
+.rst-content .important,
+.rst-content .tip,
+.rst-content .warning,
+.rst-content .seealso,
+.rst-content .admonition-todo {
+ padding: 12px;
+ line-height: 24px;
+ margin-bottom: 24px;
+ background: #e7f2fa
+}
+
+.wy-alert-title,
+.rst-content .admonition-title {
+ color: #fff;
+ font-weight: bold;
+ display: block;
+ color: #fff;
+ background: #6ab0de;
+ margin: -12px;
+ padding: 6px 12px;
+ margin-bottom: 12px
+}
+
+.wy-alert.wy-alert-danger,
+.rst-content .wy-alert-danger.note,
+.rst-content .wy-alert-danger.attention,
+.rst-content .wy-alert-danger.caution,
+.rst-content .danger,
+.rst-content .error,
+.rst-content .wy-alert-danger.hint,
+.rst-content .wy-alert-danger.important,
+.rst-content .wy-alert-danger.tip,
+.rst-content .wy-alert-danger.warning,
+.rst-content .wy-alert-danger.seealso,
+.rst-content .wy-alert-danger.admonition-todo {
+ background: #fdf3f2
+}
+
+.wy-alert.wy-alert-danger .wy-alert-title,
+.rst-content .wy-alert-danger.note .wy-alert-title,
+.rst-content .wy-alert-danger.attention .wy-alert-title,
+.rst-content .wy-alert-danger.caution .wy-alert-title,
+.rst-content .danger .wy-alert-title,
+.rst-content .error .wy-alert-title,
+.rst-content .wy-alert-danger.hint .wy-alert-title,
+.rst-content .wy-alert-danger.important .wy-alert-title,
+.rst-content .wy-alert-danger.tip .wy-alert-title,
+.rst-content .wy-alert-danger.warning .wy-alert-title,
+.rst-content .wy-alert-danger.seealso .wy-alert-title,
+.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,
+.wy-alert.wy-alert-danger .rst-content .admonition-title,
+.rst-content .wy-alert.wy-alert-danger .admonition-title,
+.rst-content .wy-alert-danger.note .admonition-title,
+.rst-content .wy-alert-danger.attention .admonition-title,
+.rst-content .wy-alert-danger.caution .admonition-title,
+.rst-content .danger .admonition-title,
+.rst-content .error .admonition-title,
+.rst-content .wy-alert-danger.hint .admonition-title,
+.rst-content .wy-alert-danger.important .admonition-title,
+.rst-content .wy-alert-danger.tip .admonition-title,
+.rst-content .wy-alert-danger.warning .admonition-title,
+.rst-content .wy-alert-danger.seealso .admonition-title,
+.rst-content .wy-alert-danger.admonition-todo .admonition-title {
+ background: #f29f97
+}
+
+.wy-alert.wy-alert-warning,
+.rst-content .wy-alert-warning.note,
+.rst-content .attention,
+.rst-content .caution,
+.rst-content .wy-alert-warning.danger,
+.rst-content .wy-alert-warning.error,
+.rst-content .wy-alert-warning.hint,
+.rst-content .wy-alert-warning.important,
+.rst-content .wy-alert-warning.tip,
+.rst-content .warning,
+.rst-content .wy-alert-warning.seealso,
+.rst-content .admonition-todo {
+ background: #ffedcc
+}
+
+.wy-alert.wy-alert-warning .wy-alert-title,
+.rst-content .wy-alert-warning.note .wy-alert-title,
+.rst-content .attention .wy-alert-title,
+.rst-content .caution .wy-alert-title,
+.rst-content .wy-alert-warning.danger .wy-alert-title,
+.rst-content .wy-alert-warning.error .wy-alert-title,
+.rst-content .wy-alert-warning.hint .wy-alert-title,
+.rst-content .wy-alert-warning.important .wy-alert-title,
+.rst-content .wy-alert-warning.tip .wy-alert-title,
+.rst-content .warning .wy-alert-title,
+.rst-content .wy-alert-warning.seealso .wy-alert-title,
+.rst-content .admonition-todo .wy-alert-title,
+.wy-alert.wy-alert-warning .rst-content .admonition-title,
+.rst-content .wy-alert.wy-alert-warning .admonition-title,
+.rst-content .wy-alert-warning.note .admonition-title,
+.rst-content .attention .admonition-title,
+.rst-content .caution .admonition-title,
+.rst-content .wy-alert-warning.danger .admonition-title,
+.rst-content .wy-alert-warning.error .admonition-title,
+.rst-content .wy-alert-warning.hint .admonition-title,
+.rst-content .wy-alert-warning.important .admonition-title,
+.rst-content .wy-alert-warning.tip .admonition-title,
+.rst-content .warning .admonition-title,
+.rst-content .wy-alert-warning.seealso .admonition-title,
+.rst-content .admonition-todo .admonition-title {
+ background: #f0b37e
+}
+
+.wy-alert.wy-alert-info,
+.rst-content .note,
+.rst-content .wy-alert-info.attention,
+.rst-content .wy-alert-info.caution,
+.rst-content .wy-alert-info.danger,
+.rst-content .wy-alert-info.error,
+.rst-content .wy-alert-info.hint,
+.rst-content .wy-alert-info.important,
+.rst-content .wy-alert-info.tip,
+.rst-content .wy-alert-info.warning,
+.rst-content .seealso,
+.rst-content .wy-alert-info.admonition-todo {
+ background: #e7f2fa
+}
+
+.wy-alert.wy-alert-info .wy-alert-title,
+.rst-content .note .wy-alert-title,
+.rst-content .wy-alert-info.attention .wy-alert-title,
+.rst-content .wy-alert-info.caution .wy-alert-title,
+.rst-content .wy-alert-info.danger .wy-alert-title,
+.rst-content .wy-alert-info.error .wy-alert-title,
+.rst-content .wy-alert-info.hint .wy-alert-title,
+.rst-content .wy-alert-info.important .wy-alert-title,
+.rst-content .wy-alert-info.tip .wy-alert-title,
+.rst-content .wy-alert-info.warning .wy-alert-title,
+.rst-content .seealso .wy-alert-title,
+.rst-content .wy-alert-info.admonition-todo .wy-alert-title,
+.wy-alert.wy-alert-info .rst-content .admonition-title,
+.rst-content .wy-alert.wy-alert-info .admonition-title,
+.rst-content .note .admonition-title,
+.rst-content .wy-alert-info.attention .admonition-title,
+.rst-content .wy-alert-info.caution .admonition-title,
+.rst-content .wy-alert-info.danger .admonition-title,
+.rst-content .wy-alert-info.error .admonition-title,
+.rst-content .wy-alert-info.hint .admonition-title,
+.rst-content .wy-alert-info.important .admonition-title,
+.rst-content .wy-alert-info.tip .admonition-title,
+.rst-content .wy-alert-info.warning .admonition-title,
+.rst-content .seealso .admonition-title,
+.rst-content .wy-alert-info.admonition-todo .admonition-title {
+ background: #6ab0de
+}
+
+.wy-alert.wy-alert-success,
+.rst-content .wy-alert-success.note,
+.rst-content .wy-alert-success.attention,
+.rst-content .wy-alert-success.caution,
+.rst-content .wy-alert-success.danger,
+.rst-content .wy-alert-success.error,
+.rst-content .hint,
+.rst-content .important,
+.rst-content .tip,
+.rst-content .wy-alert-success.warning,
+.rst-content .wy-alert-success.seealso,
+.rst-content .wy-alert-success.admonition-todo {
+ background: #dbfaf4
+}
+
+.wy-alert.wy-alert-success .wy-alert-title,
+.rst-content .wy-alert-success.note .wy-alert-title,
+.rst-content .wy-alert-success.attention .wy-alert-title,
+.rst-content .wy-alert-success.caution .wy-alert-title,
+.rst-content .wy-alert-success.danger .wy-alert-title,
+.rst-content .wy-alert-success.error .wy-alert-title,
+.rst-content .hint .wy-alert-title,
+.rst-content .important .wy-alert-title,
+.rst-content .tip .wy-alert-title,
+.rst-content .wy-alert-success.warning .wy-alert-title,
+.rst-content .wy-alert-success.seealso .wy-alert-title,
+.rst-content .wy-alert-success.admonition-todo .wy-alert-title,
+.wy-alert.wy-alert-success .rst-content .admonition-title,
+.rst-content .wy-alert.wy-alert-success .admonition-title,
+.rst-content .wy-alert-success.note .admonition-title,
+.rst-content .wy-alert-success.attention .admonition-title,
+.rst-content .wy-alert-success.caution .admonition-title,
+.rst-content .wy-alert-success.danger .admonition-title,
+.rst-content .wy-alert-success.error .admonition-title,
+.rst-content .hint .admonition-title,
+.rst-content .important .admonition-title,
+.rst-content .tip .admonition-title,
+.rst-content .wy-alert-success.warning .admonition-title,
+.rst-content .wy-alert-success.seealso .admonition-title,
+.rst-content .wy-alert-success.admonition-todo .admonition-title {
+ background: #1abc9c
+}
+
+.wy-alert.wy-alert-neutral,
+.rst-content .wy-alert-neutral.note,
+.rst-content .wy-alert-neutral.attention,
+.rst-content .wy-alert-neutral.caution,
+.rst-content .wy-alert-neutral.danger,
+.rst-content .wy-alert-neutral.error,
+.rst-content .wy-alert-neutral.hint,
+.rst-content .wy-alert-neutral.important,
+.rst-content .wy-alert-neutral.tip,
+.rst-content .wy-alert-neutral.warning,
+.rst-content .wy-alert-neutral.seealso,
+.rst-content .wy-alert-neutral.admonition-todo {
+ background: #f3f6f6
+}
+
+.wy-alert.wy-alert-neutral .wy-alert-title,
+.rst-content .wy-alert-neutral.note .wy-alert-title,
+.rst-content .wy-alert-neutral.attention .wy-alert-title,
+.rst-content .wy-alert-neutral.caution .wy-alert-title,
+.rst-content .wy-alert-neutral.danger .wy-alert-title,
+.rst-content .wy-alert-neutral.error .wy-alert-title,
+.rst-content .wy-alert-neutral.hint .wy-alert-title,
+.rst-content .wy-alert-neutral.important .wy-alert-title,
+.rst-content .wy-alert-neutral.tip .wy-alert-title,
+.rst-content .wy-alert-neutral.warning .wy-alert-title,
+.rst-content .wy-alert-neutral.seealso .wy-alert-title,
+.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,
+.wy-alert.wy-alert-neutral .rst-content .admonition-title,
+.rst-content .wy-alert.wy-alert-neutral .admonition-title,
+.rst-content .wy-alert-neutral.note .admonition-title,
+.rst-content .wy-alert-neutral.attention .admonition-title,
+.rst-content .wy-alert-neutral.caution .admonition-title,
+.rst-content .wy-alert-neutral.danger .admonition-title,
+.rst-content .wy-alert-neutral.error .admonition-title,
+.rst-content .wy-alert-neutral.hint .admonition-title,
+.rst-content .wy-alert-neutral.important .admonition-title,
+.rst-content .wy-alert-neutral.tip .admonition-title,
+.rst-content .wy-alert-neutral.warning .admonition-title,
+.rst-content .wy-alert-neutral.seealso .admonition-title,
+.rst-content .wy-alert-neutral.admonition-todo .admonition-title {
+ color: #404040;
+ background: #e1e4e5
+}
+
+.wy-alert.wy-alert-neutral a,
+.rst-content .wy-alert-neutral.note a,
+.rst-content .wy-alert-neutral.attention a,
+.rst-content .wy-alert-neutral.caution a,
+.rst-content .wy-alert-neutral.danger a,
+.rst-content .wy-alert-neutral.error a,
+.rst-content .wy-alert-neutral.hint a,
+.rst-content .wy-alert-neutral.important a,
+.rst-content .wy-alert-neutral.tip a,
+.rst-content .wy-alert-neutral.warning a,
+.rst-content .wy-alert-neutral.seealso a,
+.rst-content .wy-alert-neutral.admonition-todo a {
+ color: #2980B9
+}
+
+.wy-alert p:last-child,
+.rst-content .note p:last-child,
+.rst-content .attention p:last-child,
+.rst-content .caution p:last-child,
+.rst-content .danger p:last-child,
+.rst-content .error p:last-child,
+.rst-content .hint p:last-child,
+.rst-content .important p:last-child,
+.rst-content .tip p:last-child,
+.rst-content .warning p:last-child,
+.rst-content .seealso p:last-child,
+.rst-content .admonition-todo p:last-child {
+ margin-bottom: 0
+}
+
+.wy-tray-container {
+ position: fixed;
+ bottom: 0px;
+ left: 0;
+ z-index: 600
+}
+
+.wy-tray-container li {
+ display: block;
+ width: 300px;
+ background: transparent;
+ color: #fff;
+ text-align: center;
+ box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.1);
+ padding: 0 24px;
+ min-width: 20%;
+ opacity: 0;
+ height: 0;
+ line-height: 56px;
+ overflow: hidden;
+ -webkit-transition: all 0.3s ease-in;
+ -moz-transition: all 0.3s ease-in;
+ transition: all 0.3s ease-in
+}
+
+.wy-tray-container li.wy-tray-item-success {
+ background: #27AE60
+}
+
+.wy-tray-container li.wy-tray-item-info {
+ background: #2980B9
+}
+
+.wy-tray-container li.wy-tray-item-warning {
+ background: #E67E22
+}
+
+.wy-tray-container li.wy-tray-item-danger {
+ background: #E74C3C
+}
+
+.wy-tray-container li.on {
+ opacity: 1;
+ height: 56px
+}
+
+@media screen and (max-width: 768px) {
+ .wy-tray-container {
+ bottom: auto;
+ top: 0;
+ width: 100%
+ }
+
+ .wy-tray-container li {
+ width: 100%
+ }
+}
+
+button {
+ font-size: 100%;
+ margin: 0;
+ vertical-align: baseline;
+ *vertical-align: middle;
+ cursor: pointer;
+ line-height: normal;
+ -webkit-appearance: button;
+ *overflow: visible
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0
+}
+
+button[disabled] {
+ cursor: default
+}
+
+.btn {
+ display: inline-block;
+ border-radius: 2px;
+ line-height: normal;
+ white-space: nowrap;
+ text-align: center;
+ cursor: pointer;
+ font-size: 100%;
+ padding: 6px 12px 8px 12px;
+ color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ background-color: #27AE60;
+ text-decoration: none;
+ font-weight: normal;
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
+ box-shadow: 0px 1px 2px -1px rgba(255, 255, 255, 0.5) inset, 0px -2px 0px 0px rgba(0, 0, 0, 0.1) inset;
+ outline-none: false;
+ vertical-align: middle;
+ *display: inline;
+ zoom: 1;
+ -webkit-user-drag: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-transition: all 0.1s linear;
+ -moz-transition: all 0.1s linear;
+ transition: all 0.1s linear
+}
+
+.btn-hover {
+ background: #2e8ece;
+ color: #fff
+}
+
+.btn:hover {
+ background: #2cc36b;
+ color: #fff
+}
+
+.btn:focus {
+ background: #2cc36b;
+ outline: 0
+}
+
+.btn:active {
+ box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset, 0px 2px 0px 0px rgba(0, 0, 0, 0.1) inset;
+ padding: 8px 12px 6px 12px
+}
+
+.btn:visited {
+ color: #fff
+}
+
+.btn:disabled {
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ filter: alpha(opacity=40);
+ opacity: 0.4;
+ cursor: not-allowed;
+ box-shadow: none
+}
+
+.btn-disabled {
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ filter: alpha(opacity=40);
+ opacity: 0.4;
+ cursor: not-allowed;
+ box-shadow: none
+}
+
+.btn-disabled:hover,
+.btn-disabled:focus,
+.btn-disabled:active {
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ filter: alpha(opacity=40);
+ opacity: 0.4;
+ cursor: not-allowed;
+ box-shadow: none
+}
+
+.btn::-moz-focus-inner {
+ padding: 0;
+ border: 0
+}
+
+.btn-small {
+ font-size: 80%
+}
+
+.btn-info {
+ background-color: #2980B9 !important
+}
+
+.btn-info:hover {
+ background-color: #2e8ece !important
+}
+
+.btn-neutral {
+ background-color: #f3f6f6 !important;
+ color: #404040 !important
+}
+
+.btn-neutral:hover {
+ background-color: #e5ebeb !important;
+ color: #404040
+}
+
+.btn-neutral:visited {
+ color: #404040 !important
+}
+
+.btn-success {
+ background-color: #27AE60 !important
+}
+
+.btn-success:hover {
+ background-color: #295 !important
+}
+
+.btn-danger {
+ background-color: #E74C3C !important
+}
+
+.btn-danger:hover {
+ background-color: #ea6153 !important
+}
+
+.btn-warning {
+ background-color: #E67E22 !important
+}
+
+.btn-warning:hover {
+ background-color: #e98b39 !important
+}
+
+.btn-invert {
+ background-color: #222
+}
+
+.btn-invert:hover {
+ background-color: #2f2f2f !important
+}
+
+.btn-link {
+ background-color: transparent !important;
+ color: #2980B9;
+ box-shadow: none;
+ border-color: transparent !important
+}
+
+.btn-link:hover {
+ background-color: transparent !important;
+ color: #409ad5 !important;
+ box-shadow: none
+}
+
+.btn-link:active {
+ background-color: transparent !important;
+ color: #409ad5 !important;
+ box-shadow: none
+}
+
+.btn-link:visited {
+ color: #9B59B6
+}
+
+.wy-btn-group .btn,
+.wy-control .btn {
+ vertical-align: middle
+}
+
+.wy-btn-group {
+ margin-bottom: 24px;
+ *zoom: 1
+}
+
+.wy-btn-group:before,
+.wy-btn-group:after {
+ display: table;
+ content: ""
+}
+
+.wy-btn-group:after {
+ clear: both
+}
+
+.wy-dropdown {
+ position: relative;
+ display: inline-block
+}
+
+.wy-dropdown-active .wy-dropdown-menu {
+ display: block
+}
+
+.wy-dropdown-menu {
+ position: absolute;
+ left: 0;
+ display: none;
+ float: left;
+ top: 100%;
+ min-width: 100%;
+ background: #fcfcfc;
+ z-index: 100;
+ border: solid 1px #cfd7dd;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
+ padding: 12px
+}
+
+.wy-dropdown-menu>dd>a {
+ display: block;
+ clear: both;
+ color: #404040;
+ white-space: nowrap;
+ font-size: 90%;
+ padding: 0 12px;
+ cursor: pointer
+}
+
+.wy-dropdown-menu>dd>a:hover {
+ background: #2980B9;
+ color: #fff
+}
+
+.wy-dropdown-menu>dd.divider {
+ border-top: solid 1px #cfd7dd;
+ margin: 6px 0
+}
+
+.wy-dropdown-menu>dd.search {
+ padding-bottom: 12px
+}
+
+.wy-dropdown-menu>dd.search input[type="search"] {
+ width: 100%
+}
+
+.wy-dropdown-menu>dd.call-to-action {
+ background: #e3e3e3;
+ text-transform: uppercase;
+ font-weight: 500;
+ font-size: 80%
+}
+
+.wy-dropdown-menu>dd.call-to-action:hover {
+ background: #e3e3e3
+}
+
+.wy-dropdown-menu>dd.call-to-action .btn {
+ color: #fff
+}
+
+.wy-dropdown.wy-dropdown-up .wy-dropdown-menu {
+ bottom: 100%;
+ top: auto;
+ left: auto;
+ right: 0
+}
+
+.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu {
+ background: #fcfcfc;
+ margin-top: 2px
+}
+
+.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a {
+ padding: 6px 12px
+}
+
+.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover {
+ background: #2980B9;
+ color: #fff
+}
+
+.wy-dropdown.wy-dropdown-left .wy-dropdown-menu {
+ right: 0;
+ left: auto;
+ text-align: right
+}
+
+.wy-dropdown-arrow:before {
+ content: " ";
+ border-bottom: 5px solid #f5f5f5;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ position: absolute;
+ display: block;
+ top: -4px;
+ left: 50%;
+ margin-left: -3px
+}
+
+.wy-dropdown-arrow.wy-dropdown-arrow-left:before {
+ left: 11px
+}
+
+.wy-form-stacked select {
+ display: block
+}
+
+.wy-form-aligned input,
+.wy-form-aligned textarea,
+.wy-form-aligned select,
+.wy-form-aligned .wy-help-inline,
+.wy-form-aligned label {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle
+}
+
+.wy-form-aligned .wy-control-group>label {
+ display: inline-block;
+ vertical-align: middle;
+ width: 10em;
+ margin: 6px 12px 0 0;
+ float: left
+}
+
+.wy-form-aligned .wy-control {
+ float: left
+}
+
+.wy-form-aligned .wy-control label {
+ display: block
+}
+
+.wy-form-aligned .wy-control select {
+ margin-top: 6px
+}
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0
+}
+
+legend {
+ display: block;
+ width: 100%;
+ border: 0;
+ padding: 0;
+ white-space: normal;
+ margin-bottom: 24px;
+ font-size: 150%;
+ *margin-left: -7px
+}
+
+label {
+ display: block;
+ margin: 0 0 0.3125em 0;
+ color: #333;
+ font-size: 90%
+}
+
+input,
+select,
+textarea {
+ font-size: 100%;
+ margin: 0;
+ vertical-align: baseline;
+ *vertical-align: middle
+}
+
+.wy-control-group {
+ margin-bottom: 24px;
+ *zoom: 1;
+ max-width: 68em;
+ margin-left: auto;
+ margin-right: auto;
+ *zoom: 1
+}
+
+.wy-control-group:before,
+.wy-control-group:after {
+ display: table;
+ content: ""
+}
+
+.wy-control-group:after {
+ clear: both
+}
+
+.wy-control-group:before,
+.wy-control-group:after {
+ display: table;
+ content: ""
+}
+
+.wy-control-group:after {
+ clear: both
+}
+
+.wy-control-group.wy-control-group-required>label:after {
+ content: " *";
+ color: #E74C3C
+}
+
+.wy-control-group .wy-form-full,
+.wy-control-group .wy-form-halves,
+.wy-control-group .wy-form-thirds {
+ padding-bottom: 12px
+}
+
+.wy-control-group .wy-form-full select,
+.wy-control-group .wy-form-halves select,
+.wy-control-group .wy-form-thirds select {
+ width: 100%
+}
+
+.wy-control-group .wy-form-full input[type="text"],
+.wy-control-group .wy-form-full input[type="password"],
+.wy-control-group .wy-form-full input[type="email"],
+.wy-control-group .wy-form-full input[type="url"],
+.wy-control-group .wy-form-full input[type="date"],
+.wy-control-group .wy-form-full input[type="month"],
+.wy-control-group .wy-form-full input[type="time"],
+.wy-control-group .wy-form-full input[type="datetime"],
+.wy-control-group .wy-form-full input[type="datetime-local"],
+.wy-control-group .wy-form-full input[type="week"],
+.wy-control-group .wy-form-full input[type="number"],
+.wy-control-group .wy-form-full input[type="search"],
+.wy-control-group .wy-form-full input[type="tel"],
+.wy-control-group .wy-form-full input[type="color"],
+.wy-control-group .wy-form-halves input[type="text"],
+.wy-control-group .wy-form-halves input[type="password"],
+.wy-control-group .wy-form-halves input[type="email"],
+.wy-control-group .wy-form-halves input[type="url"],
+.wy-control-group .wy-form-halves input[type="date"],
+.wy-control-group .wy-form-halves input[type="month"],
+.wy-control-group .wy-form-halves input[type="time"],
+.wy-control-group .wy-form-halves input[type="datetime"],
+.wy-control-group .wy-form-halves input[type="datetime-local"],
+.wy-control-group .wy-form-halves input[type="week"],
+.wy-control-group .wy-form-halves input[type="number"],
+.wy-control-group .wy-form-halves input[type="search"],
+.wy-control-group .wy-form-halves input[type="tel"],
+.wy-control-group .wy-form-halves input[type="color"],
+.wy-control-group .wy-form-thirds input[type="text"],
+.wy-control-group .wy-form-thirds input[type="password"],
+.wy-control-group .wy-form-thirds input[type="email"],
+.wy-control-group .wy-form-thirds input[type="url"],
+.wy-control-group .wy-form-thirds input[type="date"],
+.wy-control-group .wy-form-thirds input[type="month"],
+.wy-control-group .wy-form-thirds input[type="time"],
+.wy-control-group .wy-form-thirds input[type="datetime"],
+.wy-control-group .wy-form-thirds input[type="datetime-local"],
+.wy-control-group .wy-form-thirds input[type="week"],
+.wy-control-group .wy-form-thirds input[type="number"],
+.wy-control-group .wy-form-thirds input[type="search"],
+.wy-control-group .wy-form-thirds input[type="tel"],
+.wy-control-group .wy-form-thirds input[type="color"] {
+ width: 100%
+}
+
+.wy-control-group .wy-form-full {
+ float: left;
+ display: block;
+ margin-right: 2.35765%;
+ width: 100%;
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-full:last-child {
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-halves {
+ float: left;
+ display: block;
+ margin-right: 2.35765%;
+ width: 48.82117%
+}
+
+.wy-control-group .wy-form-halves:last-child {
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-halves:nth-of-type(2n) {
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-halves:nth-of-type(2n+1) {
+ clear: left
+}
+
+.wy-control-group .wy-form-thirds {
+ float: left;
+ display: block;
+ margin-right: 2.35765%;
+ width: 31.76157%
+}
+
+.wy-control-group .wy-form-thirds:last-child {
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-thirds:nth-of-type(3n) {
+ margin-right: 0
+}
+
+.wy-control-group .wy-form-thirds:nth-of-type(3n+1) {
+ clear: left
+}
+
+.wy-control-group.wy-control-group-no-input .wy-control {
+ margin: 6px 0 0 0;
+ font-size: 90%
+}
+
+.wy-control-no-input {
+ display: inline-block;
+ margin: 6px 0 0 0;
+ font-size: 90%
+}
+
+.wy-control-group.fluid-input input[type="text"],
+.wy-control-group.fluid-input input[type="password"],
+.wy-control-group.fluid-input input[type="email"],
+.wy-control-group.fluid-input input[type="url"],
+.wy-control-group.fluid-input input[type="date"],
+.wy-control-group.fluid-input input[type="month"],
+.wy-control-group.fluid-input input[type="time"],
+.wy-control-group.fluid-input input[type="datetime"],
+.wy-control-group.fluid-input input[type="datetime-local"],
+.wy-control-group.fluid-input input[type="week"],
+.wy-control-group.fluid-input input[type="number"],
+.wy-control-group.fluid-input input[type="search"],
+.wy-control-group.fluid-input input[type="tel"],
+.wy-control-group.fluid-input input[type="color"] {
+ width: 100%
+}
+
+.wy-form-message-inline {
+ display: inline-block;
+ padding-left: 0.3em;
+ color: #666;
+ vertical-align: middle;
+ font-size: 90%
+}
+
+.wy-form-message {
+ display: block;
+ color: #999;
+ font-size: 70%;
+ margin-top: 0.3125em;
+ font-style: italic
+}
+
+.wy-form-message p {
+ font-size: inherit;
+ font-style: italic;
+ margin-bottom: 6px
+}
+
+.wy-form-message p:last-child {
+ margin-bottom: 0
+}
+
+input {
+ line-height: normal
+}
+
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
+ *overflow: visible
+}
+
+input[type="text"],
+input[type="password"],
+input[type="email"],
+input[type="url"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="week"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="color"] {
+ -webkit-appearance: none;
+ padding: 6px;
+ display: inline-block;
+ border: 1px solid #ccc;
+ font-size: 80%;
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
+ box-shadow: inset 0 1px 3px #ddd;
+ border-radius: 0;
+ -webkit-transition: border 0.3s linear;
+ -moz-transition: border 0.3s linear;
+ transition: border 0.3s linear
+}
+
+input[type="datetime-local"] {
+ padding: 0.34375em 0.625em
+}
+
+input[disabled] {
+ cursor: default
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0;
+ margin-right: 0.3125em;
+ *height: 13px;
+ *width: 13px
+}
+
+input[type="search"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box
+}
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none
+}
+
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="email"]:focus,
+input[type="url"]:focus,
+input[type="date"]:focus,
+input[type="month"]:focus,
+input[type="time"]:focus,
+input[type="datetime"]:focus,
+input[type="datetime-local"]:focus,
+input[type="week"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="color"]:focus {
+ outline: 0;
+ outline: thin dotted \9;
+ border-color: #333
+}
+
+input.no-focus:focus {
+ border-color: #ccc !important
+}
+
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted #333;
+ outline: 1px auto #129FEA
+}
+
+input[type="text"][disabled],
+input[type="password"][disabled],
+input[type="email"][disabled],
+input[type="url"][disabled],
+input[type="date"][disabled],
+input[type="month"][disabled],
+input[type="time"][disabled],
+input[type="datetime"][disabled],
+input[type="datetime-local"][disabled],
+input[type="week"][disabled],
+input[type="number"][disabled],
+input[type="search"][disabled],
+input[type="tel"][disabled],
+input[type="color"][disabled] {
+ cursor: not-allowed;
+ background-color: #fafafa
+}
+
+input:focus:invalid,
+textarea:focus:invalid,
+select:focus:invalid {
+ color: #E74C3C;
+ border: 1px solid #E74C3C
+}
+
+input:focus:invalid:focus,
+textarea:focus:invalid:focus,
+select:focus:invalid:focus {
+ border-color: #E74C3C
+}
+
+input[type="file"]:focus:invalid:focus,
+input[type="radio"]:focus:invalid:focus,
+input[type="checkbox"]:focus:invalid:focus {
+ outline-color: #E74C3C
+}
+
+input.wy-input-large {
+ padding: 12px;
+ font-size: 100%
+}
+
+textarea {
+ overflow: auto;
+ vertical-align: top;
+ width: 100%;
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif
+}
+
+select,
+textarea {
+ padding: 0.5em 0.625em;
+ display: inline-block;
+ border: 1px solid #ccc;
+ font-size: 80%;
+ box-shadow: inset 0 1px 3px #ddd;
+ -webkit-transition: border 0.3s linear;
+ -moz-transition: border 0.3s linear;
+ transition: border 0.3s linear
+}
+
+select {
+ border: 1px solid #ccc;
+ background-color: #fff
+}
+
+select[multiple] {
+ height: auto
+}
+
+select:focus,
+textarea:focus {
+ outline: 0
+}
+
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ cursor: not-allowed;
+ background-color: #fafafa
+}
+
+input[type="radio"][disabled],
+input[type="checkbox"][disabled] {
+ cursor: not-allowed
+}
+
+.wy-checkbox,
+.wy-radio {
+ margin: 6px 0;
+ color: #404040;
+ display: block
+}
+
+.wy-checkbox input,
+.wy-radio input {
+ vertical-align: baseline
+}
+
+.wy-form-message-inline {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: middle
+}
+
+.wy-input-prefix,
+.wy-input-suffix {
+ white-space: nowrap;
+ padding: 6px
+}
+
+.wy-input-prefix .wy-input-context,
+.wy-input-suffix .wy-input-context {
+ line-height: 27px;
+ padding: 0 8px;
+ display: inline-block;
+ font-size: 80%;
+ background-color: #f3f6f6;
+ border: solid 1px #ccc;
+ color: #999
+}
+
+.wy-input-suffix .wy-input-context {
+ border-left: 0
+}
+
+.wy-input-prefix .wy-input-context {
+ border-right: 0
+}
+
+.wy-switch {
+ width: 36px;
+ height: 12px;
+ margin: 12px 0;
+ position: relative;
+ border-radius: 4px;
+ background: #ccc;
+ cursor: pointer;
+ -webkit-transition: all 0.2s ease-in-out;
+ -moz-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out
+}
+
+.wy-switch:before {
+ position: absolute;
+ content: "";
+ display: block;
+ width: 18px;
+ height: 18px;
+ border-radius: 4px;
+ background: #999;
+ left: -3px;
+ top: -3px;
+ -webkit-transition: all 0.2s ease-in-out;
+ -moz-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out
+}
+
+.wy-switch:after {
+ content: "false";
+ position: absolute;
+ left: 48px;
+ display: block;
+ font-size: 12px;
+ color: #ccc
+}
+
+.wy-switch.active {
+ background: #1e8449
+}
+
+.wy-switch.active:before {
+ left: 24px;
+ background: #27AE60
+}
+
+.wy-switch.active:after {
+ content: "true"
+}
+
+.wy-switch.disabled,
+.wy-switch.active.disabled {
+ cursor: not-allowed
+}
+
+.wy-control-group.wy-control-group-error .wy-form-message,
+.wy-control-group.wy-control-group-error>label {
+ color: #E74C3C
+}
+
+.wy-control-group.wy-control-group-error input[type="text"],
+.wy-control-group.wy-control-group-error input[type="password"],
+.wy-control-group.wy-control-group-error input[type="email"],
+.wy-control-group.wy-control-group-error input[type="url"],
+.wy-control-group.wy-control-group-error input[type="date"],
+.wy-control-group.wy-control-group-error input[type="month"],
+.wy-control-group.wy-control-group-error input[type="time"],
+.wy-control-group.wy-control-group-error input[type="datetime"],
+.wy-control-group.wy-control-group-error input[type="datetime-local"],
+.wy-control-group.wy-control-group-error input[type="week"],
+.wy-control-group.wy-control-group-error input[type="number"],
+.wy-control-group.wy-control-group-error input[type="search"],
+.wy-control-group.wy-control-group-error input[type="tel"],
+.wy-control-group.wy-control-group-error input[type="color"] {
+ border: solid 1px #E74C3C
+}
+
+.wy-control-group.wy-control-group-error textarea {
+ border: solid 1px #E74C3C
+}
+
+.wy-inline-validate {
+ white-space: nowrap
+}
+
+.wy-inline-validate .wy-input-context {
+ padding: 0.5em 0.625em;
+ display: inline-block;
+ font-size: 80%
+}
+
+.wy-inline-validate.wy-inline-validate-success .wy-input-context {
+ color: #27AE60
+}
+
+.wy-inline-validate.wy-inline-validate-danger .wy-input-context {
+ color: #E74C3C
+}
+
+.wy-inline-validate.wy-inline-validate-warning .wy-input-context {
+ color: #E67E22
+}
+
+.wy-inline-validate.wy-inline-validate-info .wy-input-context {
+ color: #2980B9
+}
+
+.rotate-90 {
+ -webkit-transform: rotate(90deg);
+ -moz-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ -o-transform: rotate(90deg);
+ transform: rotate(90deg)
+}
+
+.rotate-180 {
+ -webkit-transform: rotate(180deg);
+ -moz-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ -o-transform: rotate(180deg);
+ transform: rotate(180deg)
+}
+
+.rotate-270 {
+ -webkit-transform: rotate(270deg);
+ -moz-transform: rotate(270deg);
+ -ms-transform: rotate(270deg);
+ -o-transform: rotate(270deg);
+ transform: rotate(270deg)
+}
+
+.mirror {
+ -webkit-transform: scaleX(-1);
+ -moz-transform: scaleX(-1);
+ -ms-transform: scaleX(-1);
+ -o-transform: scaleX(-1);
+ transform: scaleX(-1)
+}
+
+.mirror.rotate-90 {
+ -webkit-transform: scaleX(-1) rotate(90deg);
+ -moz-transform: scaleX(-1) rotate(90deg);
+ -ms-transform: scaleX(-1) rotate(90deg);
+ -o-transform: scaleX(-1) rotate(90deg);
+ transform: scaleX(-1) rotate(90deg)
+}
+
+.mirror.rotate-180 {
+ -webkit-transform: scaleX(-1) rotate(180deg);
+ -moz-transform: scaleX(-1) rotate(180deg);
+ -ms-transform: scaleX(-1) rotate(180deg);
+ -o-transform: scaleX(-1) rotate(180deg);
+ transform: scaleX(-1) rotate(180deg)
+}
+
+.mirror.rotate-270 {
+ -webkit-transform: scaleX(-1) rotate(270deg);
+ -moz-transform: scaleX(-1) rotate(270deg);
+ -ms-transform: scaleX(-1) rotate(270deg);
+ -o-transform: scaleX(-1) rotate(270deg);
+ transform: scaleX(-1) rotate(270deg)
+}
+
+@media only screen and (max-width: 480px) {
+ .wy-form button[type="submit"] {
+ margin: 0.7em 0 0
+ }
+
+ .wy-form input[type="text"],
+ .wy-form input[type="password"],
+ .wy-form input[type="email"],
+ .wy-form input[type="url"],
+ .wy-form input[type="date"],
+ .wy-form input[type="month"],
+ .wy-form input[type="time"],
+ .wy-form input[type="datetime"],
+ .wy-form input[type="datetime-local"],
+ .wy-form input[type="week"],
+ .wy-form input[type="number"],
+ .wy-form input[type="search"],
+ .wy-form input[type="tel"],
+ .wy-form input[type="color"] {
+ margin-bottom: 0.3em;
+ display: block
+ }
+
+ .wy-form label {
+ margin-bottom: 0.3em;
+ display: block
+ }
+
+ .wy-form input[type="password"],
+ .wy-form input[type="email"],
+ .wy-form input[type="url"],
+ .wy-form input[type="date"],
+ .wy-form input[type="month"],
+ .wy-form input[type="time"],
+ .wy-form input[type="datetime"],
+ .wy-form input[type="datetime-local"],
+ .wy-form input[type="week"],
+ .wy-form input[type="number"],
+ .wy-form input[type="search"],
+ .wy-form input[type="tel"],
+ .wy-form input[type="color"] {
+ margin-bottom: 0
+ }
+
+ .wy-form-aligned .wy-control-group label {
+ margin-bottom: 0.3em;
+ text-align: left;
+ display: block;
+ width: 100%
+ }
+
+ .wy-form-aligned .wy-control {
+ margin: 1.5em 0 0 0
+ }
+
+ .wy-form .wy-help-inline,
+ .wy-form-message-inline,
+ .wy-form-message {
+ display: block;
+ font-size: 80%;
+ padding: 6px 0
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .tablet-hide {
+ display: none
+ }
+}
+
+@media screen and (max-width: 480px) {
+ .mobile-hide {
+ display: none
+ }
+}
+
+.float-left {
+ float: left
+}
+
+.float-right {
+ float: right
+}
+
+.full-width {
+ width: 100%
+}
+
+.wy-table,
+.rst-content table.docutils,
+.rst-content table.field-list {
+ border-collapse: collapse;
+ border-spacing: 0;
+ empty-cells: show;
+ margin-bottom: 24px
+}
+
+.wy-table caption,
+.rst-content table.docutils caption,
+.rst-content table.field-list caption {
+ color: #000;
+ font: italic 85%/1 arial, sans-serif;
+ padding: 1em 0;
+ text-align: center
+}
+
+.wy-table td,
+.rst-content table.docutils td,
+.rst-content table.field-list td,
+.wy-table th,
+.rst-content table.docutils th,
+.rst-content table.field-list th {
+ font-size: 90%;
+ margin: 0;
+ overflow: visible;
+ padding: 8px 16px
+}
+
+.wy-table td:first-child,
+.rst-content table.docutils td:first-child,
+.rst-content table.field-list td:first-child,
+.wy-table th:first-child,
+.rst-content table.docutils th:first-child,
+.rst-content table.field-list th:first-child {
+ border-left-width: 0
+}
+
+.wy-table thead,
+.rst-content table.docutils thead,
+.rst-content table.field-list thead {
+ color: #000;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap
+}
+
+.wy-table thead th,
+.rst-content table.docutils thead th,
+.rst-content table.field-list thead th {
+ font-weight: bold;
+ border-bottom: solid 2px #e1e4e5
+}
+
+.wy-table td,
+.rst-content table.docutils td,
+.rst-content table.field-list td {
+ background-color: transparent;
+ vertical-align: middle
+}
+
+.wy-table td p,
+.rst-content table.docutils td p,
+.rst-content table.field-list td p {
+ line-height: 18px
+}
+
+.wy-table td p:last-child,
+.rst-content table.docutils td p:last-child,
+.rst-content table.field-list td p:last-child {
+ margin-bottom: 0
+}
+
+.wy-table .wy-table-cell-min,
+.rst-content table.docutils .wy-table-cell-min,
+.rst-content table.field-list .wy-table-cell-min {
+ width: 1%;
+ padding-right: 0
+}
+
+.wy-table .wy-table-cell-min input[type=checkbox],
+.rst-content table.docutils .wy-table-cell-min input[type=checkbox],
+.rst-content table.field-list .wy-table-cell-min input[type=checkbox],
+.wy-table .wy-table-cell-min input[type=checkbox],
+.rst-content table.docutils .wy-table-cell-min input[type=checkbox],
+.rst-content table.field-list .wy-table-cell-min input[type=checkbox] {
+ margin: 0
+}
+
+.wy-table-secondary {
+ color: gray;
+ font-size: 90%
+}
+
+.wy-table-tertiary {
+ color: gray;
+ font-size: 80%
+}
+
+.wy-table-odd td,
+.wy-table-striped tr:nth-child(2n-1) td,
+.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
+ background-color: #f3f6f6
+}
+
+.wy-table-backed {
+ background-color: #f3f6f6
+}
+
+.wy-table-bordered-all,
+.rst-content table.docutils {
+ border: 1px solid #e1e4e5
+}
+
+.wy-table-bordered-all td,
+.rst-content table.docutils td {
+ border-bottom: 1px solid #e1e4e5;
+ border-left: 1px solid #e1e4e5
+}
+
+.wy-table-bordered-all tbody>tr:last-child td,
+.rst-content table.docutils tbody>tr:last-child td {
+ border-bottom-width: 0
+}
+
+.wy-table-bordered {
+ border: 1px solid #e1e4e5
+}
+
+.wy-table-bordered-rows td {
+ border-bottom: 1px solid #e1e4e5
+}
+
+.wy-table-bordered-rows tbody>tr:last-child td {
+ border-bottom-width: 0
+}
+
+.wy-table-horizontal tbody>tr:last-child td {
+ border-bottom-width: 0
+}
+
+.wy-table-horizontal td,
+.wy-table-horizontal th {
+ border-width: 0 0 1px 0;
+ border-bottom: 1px solid #e1e4e5
+}
+
+.wy-table-horizontal tbody>tr:last-child td {
+ border-bottom-width: 0
+}
+
+.wy-table-responsive {
+ margin-bottom: 24px;
+ max-width: 100%;
+ overflow: auto
+}
+
+.wy-table-responsive table {
+ margin-bottom: 0 !important
+}
+
+.wy-table-responsive table td,
+.wy-table-responsive table th {
+ white-space: nowrap
+}
+
+a {
+ color: #2980B9;
+ text-decoration: none;
+ cursor: pointer
+}
+
+a:hover {
+ color: #3091d1
+}
+
+a:visited {
+ color: #9B59B6
+}
+
+html {
+ height: 100%;
+ overflow-x: hidden
+}
+
+body {
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
+ font-weight: normal;
+ color: #404040;
+ min-height: 100%;
+ overflow-x: hidden;
+ background: #edf0f2
+}
+
+.wy-text-left {
+ text-align: left
+}
+
+.wy-text-center {
+ text-align: center
+}
+
+.wy-text-right {
+ text-align: right
+}
+
+.wy-text-large {
+ font-size: 120%
+}
+
+.wy-text-normal {
+ font-size: 100%
+}
+
+.wy-text-small,
+small {
+ font-size: 80%
+}
+
+.wy-text-strike {
+ text-decoration: line-through
+}
+
+.wy-text-warning {
+ color: #E67E22 !important
+}
+
+a.wy-text-warning:hover {
+ color: #eb9950 !important
+}
+
+.wy-text-info {
+ color: #2980B9 !important
+}
+
+a.wy-text-info:hover {
+ color: #409ad5 !important
+}
+
+.wy-text-success {
+ color: #27AE60 !important
+}
+
+a.wy-text-success:hover {
+ color: #36d278 !important
+}
+
+.wy-text-danger {
+ color: #E74C3C !important
+}
+
+a.wy-text-danger:hover {
+ color: #ed7669 !important
+}
+
+.wy-text-neutral {
+ color: #404040 !important
+}
+
+a.wy-text-neutral:hover {
+ color: #595959 !important
+}
+
+h1,
+h2,
+.rst-content .toctree-wrapper p.caption,
+h3,
+h4,
+h5,
+h6,
+legend {
+ margin-top: 0;
+ font-weight: 700;
+ font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif
+}
+
+p {
+ line-height: 24px;
+ margin: 0;
+ font-size: 16px;
+ margin-bottom: 24px
+}
+
+h1 {
+ font-size: 175%
+}
+
+h2,
+.rst-content .toctree-wrapper p.caption {
+ font-size: 150%
+}
+
+h3 {
+ font-size: 125%
+}
+
+h4 {
+ font-size: 115%
+}
+
+h5 {
+ font-size: 110%
+}
+
+h6 {
+ font-size: 100%
+}
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #e1e4e5;
+ margin: 24px 0;
+ padding: 0
+}
+
+code,
+.rst-content tt,
+.rst-content code {
+ white-space: nowrap;
+ max-width: 100%;
+ background: #fff;
+ border: solid 1px #e1e4e5;
+ font-size: 75%;
+ padding: 0 5px;
+ font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace;
+ color: #E74C3C;
+ overflow-x: auto
+}
+
+code.code-large,
+.rst-content tt.code-large {
+ font-size: 90%
+}
+
+.wy-plain-list-disc,
+.rst-content .section ul,
+.rst-content .toctree-wrapper ul,
+article ul {
+ list-style: disc;
+ line-height: 24px;
+ margin-bottom: 24px
+}
+
+.wy-plain-list-disc li,
+.rst-content .section ul li,
+.rst-content .toctree-wrapper ul li,
+article ul li {
+ list-style: disc;
+ margin-left: 24px
+}
+
+.wy-plain-list-disc li p:last-child,
+.rst-content .section ul li p:last-child,
+.rst-content .toctree-wrapper ul li p:last-child,
+article ul li p:last-child {
+ margin-bottom: 0
+}
+
+.wy-plain-list-disc li ul,
+.rst-content .section ul li ul,
+.rst-content .toctree-wrapper ul li ul,
+article ul li ul {
+ margin-bottom: 0
+}
+
+.wy-plain-list-disc li li,
+.rst-content .section ul li li,
+.rst-content .toctree-wrapper ul li li,
+article ul li li {
+ list-style: circle
+}
+
+.wy-plain-list-disc li li li,
+.rst-content .section ul li li li,
+.rst-content .toctree-wrapper ul li li li,
+article ul li li li {
+ list-style: square
+}
+
+.wy-plain-list-disc li ol li,
+.rst-content .section ul li ol li,
+.rst-content .toctree-wrapper ul li ol li,
+article ul li ol li {
+ list-style: decimal
+}
+
+.wy-plain-list-decimal,
+.rst-content .section ol,
+.rst-content ol.arabic,
+article ol {
+ list-style: decimal;
+ line-height: 24px;
+ margin-bottom: 24px
+}
+
+.wy-plain-list-decimal li,
+.rst-content .section ol li,
+.rst-content ol.arabic li,
+article ol li {
+ list-style: decimal;
+ margin-left: 24px
+}
+
+.wy-plain-list-decimal li p:last-child,
+.rst-content .section ol li p:last-child,
+.rst-content ol.arabic li p:last-child,
+article ol li p:last-child {
+ margin-bottom: 0
+}
+
+.wy-plain-list-decimal li ul,
+.rst-content .section ol li ul,
+.rst-content ol.arabic li ul,
+article ol li ul {
+ margin-bottom: 0
+}
+
+.wy-plain-list-decimal li ul li,
+.rst-content .section ol li ul li,
+.rst-content ol.arabic li ul li,
+article ol li ul li {
+ list-style: disc
+}
+
+.codeblock-example {
+ border: 1px solid #e1e4e5;
+ border-bottom: none;
+ padding: 24px;
+ padding-top: 48px;
+ font-weight: 500;
+ background: #fff;
+ position: relative
+}
+
+.codeblock-example:after {
+ content: "Example";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ background: #9B59B6;
+ color: #fff;
+ padding: 6px 12px
+}
+
+.codeblock-example.prettyprint-example-only {
+ border: 1px solid #e1e4e5;
+ margin-bottom: 24px
+}
+
+.codeblock,
+pre.literal-block,
+.rst-content .literal-block,
+.rst-content pre.literal-block,
+div[class^='highlight'] {
+ border: 1px solid #e1e4e5;
+ padding: 0px;
+ overflow-x: auto;
+ background: #fff;
+ margin: 1px 0 24px 0
+}
+
+.codeblock div[class^='highlight'],
+pre.literal-block div[class^='highlight'],
+.rst-content .literal-block div[class^='highlight'],
+div[class^='highlight'] div[class^='highlight'] {
+ border: none;
+ background: none;
+ margin: 0
+}
+
+div[class^='highlight'] td.code {
+ width: 100%
+}
+
+.linenodiv pre {
+ border-right: solid 1px #e6e9ea;
+ margin: 0;
+ padding: 12px 12px;
+ font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace;
+ font-size: 12px;
+ line-height: 1.5;
+ color: #d9d9d9
+}
+
+div[class^='highlight'] pre {
+ white-space: pre;
+ margin: 0;
+ padding: 12px 12px;
+ font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace;
+ font-size: 12px;
+ line-height: 1.5;
+ display: block;
+ overflow: auto;
+ color: #404040
+}
+
+@media print {
+
+ .codeblock,
+ pre.literal-block,
+ .rst-content .literal-block,
+ .rst-content pre.literal-block,
+ div[class^='highlight'],
+ div[class^='highlight'] pre {
+ white-space: pre-wrap
+ }
+}
+
+.hll {
+ background-color: #ffc;
+ margin: 0 -12px;
+ padding: 0 12px;
+ display: block
+}
+
+.c {
+ color: #998;
+ font-style: italic
+}
+
+.err {
+ color: #a61717;
+ background-color: #e3d2d2
+}
+
+.k {
+ font-weight: bold
+}
+
+.o {
+ font-weight: bold
+}
+
+.cm {
+ color: #998;
+ font-style: italic
+}
+
+.cp {
+ color: #999;
+ font-weight: bold
+}
+
+.c1 {
+ color: #998;
+ font-style: italic
+}
+
+.cs {
+ color: #999;
+ font-weight: bold;
+ font-style: italic
+}
+
+.gd {
+ color: #000;
+ background-color: #fdd
+}
+
+.gd .x {
+ color: #000;
+ background-color: #faa
+}
+
+.ge {
+ font-style: italic
+}
+
+.gr {
+ color: #a00
+}
+
+.gh {
+ color: #999
+}
+
+.gi {
+ color: #000;
+ background-color: #dfd
+}
+
+.gi .x {
+ color: #000;
+ background-color: #afa
+}
+
+.go {
+ color: #888
+}
+
+.gp {
+ color: #555
+}
+
+.gs {
+ font-weight: bold
+}
+
+.gu {
+ color: purple;
+ font-weight: bold
+}
+
+.gt {
+ color: #a00
+}
+
+.kc {
+ font-weight: bold
+}
+
+.kd {
+ font-weight: bold
+}
+
+.kn {
+ font-weight: bold
+}
+
+.kp {
+ font-weight: bold
+}
+
+.kr {
+ font-weight: bold
+}
+
+.kt {
+ color: #458;
+ font-weight: bold
+}
+
+.m {
+ color: #099
+}
+
+.s {
+ color: #d14
+}
+
+.n {
+ color: #333
+}
+
+.na {
+ color: teal
+}
+
+.nb {
+ color: #0086b3
+}
+
+.nc {
+ color: #458;
+ font-weight: bold
+}
+
+.no {
+ color: teal
+}
+
+.ni {
+ color: purple
+}
+
+.ne {
+ color: #900;
+ font-weight: bold
+}
+
+.nf {
+ color: #900;
+ font-weight: bold
+}
+
+.nn {
+ color: #555
+}
+
+.nt {
+ color: navy
+}
+
+.nv {
+ color: teal
+}
+
+.ow {
+ font-weight: bold
+}
+
+.w {
+ color: #bbb
+}
+
+.mf {
+ color: #099
+}
+
+.mh {
+ color: #099
+}
+
+.mi {
+ color: #099
+}
+
+.mo {
+ color: #099
+}
+
+.sb {
+ color: #d14
+}
+
+.sc {
+ color: #d14
+}
+
+.sd {
+ color: #d14
+}
+
+.s2 {
+ color: #d14
+}
+
+.se {
+ color: #d14
+}
+
+.sh {
+ color: #d14
+}
+
+.si {
+ color: #d14
+}
+
+.sx {
+ color: #d14
+}
+
+.sr {
+ color: #009926
+}
+
+.s1 {
+ color: #d14
+}
+
+.ss {
+ color: #990073
+}
+
+.bp {
+ color: #999
+}
+
+.vc {
+ color: teal
+}
+
+.vg {
+ color: teal
+}
+
+.vi {
+ color: teal
+}
+
+.il {
+ color: #099
+}
+
+.gc {
+ color: #999;
+ background-color: #EAF2F5
+}
+
+.wy-breadcrumbs li {
+ display: inline-block
+}
+
+.wy-breadcrumbs li.wy-breadcrumbs-aside {
+ float: right
+}
+
+.wy-breadcrumbs li a {
+ display: inline-block;
+ padding: 5px
+}
+
+.wy-breadcrumbs li a:first-child {
+ padding-left: 0
+}
+
+.wy-breadcrumbs li code,
+.wy-breadcrumbs li .rst-content tt,
+.rst-content .wy-breadcrumbs li tt {
+ padding: 5px;
+ border: none;
+ background: none
+}
+
+.wy-breadcrumbs li code.literal,
+.wy-breadcrumbs li .rst-content tt.literal,
+.rst-content .wy-breadcrumbs li tt.literal {
+ color: #404040
+}
+
+.wy-breadcrumbs-extra {
+ margin-bottom: 0;
+ color: #b3b3b3;
+ font-size: 80%;
+ display: inline-block
+}
+
+@media screen and (max-width: 480px) {
+ .wy-breadcrumbs-extra {
+ display: none
+ }
+
+ .wy-breadcrumbs li.wy-breadcrumbs-aside {
+ display: none
+ }
+}
+
+@media print {
+ .wy-breadcrumbs li.wy-breadcrumbs-aside {
+ display: none
+ }
+}
+
+.wy-affix {
+ position: fixed;
+ top: 1.618em
+}
+
+.wy-menu a:hover {
+ text-decoration: none
+}
+
+.wy-menu-horiz {
+ *zoom: 1
+}
+
+.wy-menu-horiz:before,
+.wy-menu-horiz:after {
+ display: table;
+ content: ""
+}
+
+.wy-menu-horiz:after {
+ clear: both
+}
+
+.wy-menu-horiz ul,
+.wy-menu-horiz li {
+ display: inline-block
+}
+
+.wy-menu-horiz li:hover {
+ background: rgba(255, 255, 255, 0.1)
+}
+
+.wy-menu-horiz li.divide-left {
+ border-left: solid 1px #404040
+}
+
+.wy-menu-horiz li.divide-right {
+ border-right: solid 1px #404040
+}
+
+.wy-menu-horiz a {
+ height: 32px;
+ display: inline-block;
+ line-height: 32px;
+ padding: 0 16px
+}
+
+.wy-menu-vertical {
+ width: 300px
+}
+
+.wy-menu-vertical header,
+.wy-menu-vertical p.caption {
+ height: 32px;
+ display: inline-block;
+ line-height: 32px;
+ padding: 0 1.618em;
+ margin-bottom: 0;
+ display: block;
+ font-weight: bold;
+ text-transform: uppercase;
+ font-size: 80%;
+ color: #555;
+ white-space: nowrap
+}
+
+.wy-menu-vertical ul {
+ margin-bottom: 0
+}
+
+.wy-menu-vertical li.divide-top {
+ border-top: solid 1px #404040
+}
+
+.wy-menu-vertical li.divide-bottom {
+ border-bottom: solid 1px #404040
+}
+
+.wy-menu-vertical li.current {
+ background: #e3e3e3
+}
+
+.wy-menu-vertical li.current a {
+ color: gray;
+ border-right: solid 1px #c9c9c9;
+ padding: 0.4045em 2.427em
+}
+
+.wy-menu-vertical li.current a:hover {
+ background: #d6d6d6
+}
+
+.wy-menu-vertical li code,
+.wy-menu-vertical li .rst-content tt,
+.rst-content .wy-menu-vertical li tt {
+ border: none;
+ background: inherit;
+ color: inherit;
+ padding-left: 0;
+ padding-right: 0
+}
+
+.wy-menu-vertical li span.toctree-expand {
+ display: block;
+ float: left;
+ margin-left: -1.2em;
+ font-size: 0.8em;
+ line-height: 1.6em;
+ color: #4d4d4d
+}
+
+.wy-menu-vertical li.on a,
+.wy-menu-vertical li.current>a {
+ color: #404040;
+ padding: 0.4045em 1.618em;
+ font-weight: bold;
+ position: relative;
+ background: #fcfcfc;
+ border: none;
+ border-bottom: solid 1px #c9c9c9;
+ border-top: solid 1px #c9c9c9;
+ padding-left: 1.618em -4px
+}
+
+.wy-menu-vertical li.on a:hover,
+.wy-menu-vertical li.current>a:hover {
+ background: #fcfcfc
+}
+
+.wy-menu-vertical li.on a:hover span.toctree-expand,
+.wy-menu-vertical li.current>a:hover span.toctree-expand {
+ color: gray
+}
+
+.wy-menu-vertical li.on a span.toctree-expand,
+.wy-menu-vertical li.current>a span.toctree-expand {
+ display: block;
+ font-size: 0.8em;
+ line-height: 1.6em;
+ color: #333
+}
+
+.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul {
+ display: none
+}
+
+.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul {
+ display: block
+}
+
+.wy-menu-vertical li.toctree-l2.current>a {
+ background: #c9c9c9;
+ padding: 0.4045em 2.427em
+}
+
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a {
+ display: block;
+ background: #c9c9c9;
+ padding: 0.4045em 4.045em
+}
+
+.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
+ color: gray
+}
+
+.wy-menu-vertical li.toctree-l2 span.toctree-expand {
+ color: #a3a3a3
+}
+
+.wy-menu-vertical li.toctree-l3 {
+ font-size: 0.9em
+}
+
+.wy-menu-vertical li.toctree-l3.current>a {
+ background: #bdbdbd;
+ padding: 0.4045em 4.045em
+}
+
+.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a {
+ display: block;
+ background: #bdbdbd;
+ padding: 0.4045em 5.663em;
+ border-top: none;
+ border-bottom: none
+}
+
+.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand {
+ color: gray
+}
+
+.wy-menu-vertical li.toctree-l3 span.toctree-expand {
+ color: #969696
+}
+
+.wy-menu-vertical li.toctree-l4 {
+ font-size: 0.9em
+}
+
+.wy-menu-vertical li.current ul {
+ display: block
+}
+
+.wy-menu-vertical li ul {
+ margin-bottom: 0;
+ display: none
+}
+
+.wy-menu-vertical .local-toc li ul {
+ display: block
+}
+
+.wy-menu-vertical li ul li a {
+ margin-bottom: 0;
+ color: #b3b3b3;
+ font-weight: normal
+}
+
+.wy-menu-vertical a {
+ display: inline-block;
+ line-height: 18px;
+ padding: 0.4045em 1.618em;
+ display: block;
+ position: relative;
+ font-size: 90%;
+ color: #b3b3b3
+}
+
+.wy-menu-vertical a:hover {
+ background-color: #4e4a4a;
+ cursor: pointer
+}
+
+.wy-menu-vertical a:hover span.toctree-expand {
+ color: #b3b3b3
+}
+
+.wy-menu-vertical a:active {
+ background-color: #2980B9;
+ cursor: pointer;
+ color: #fff
+}
+
+.wy-menu-vertical a:active span.toctree-expand {
+ color: #fff
+}
+
+.wy-side-nav-search {
+ display: block;
+ width: 300px;
+ padding: 0.809em;
+ margin-bottom: 0.809em;
+ z-index: 200;
+ background-color: #2980B9;
+ text-align: center;
+ padding: 0.809em;
+ display: block;
+ color: #fcfcfc;
+ margin-bottom: 0.809em
+}
+
+.wy-side-nav-search input[type=text] {
+ width: 100%;
+ border-radius: 50px;
+ padding: 6px 12px;
+ border-color: #2472a4
+}
+
+.wy-side-nav-search img {
+ display: block;
+ margin: auto auto 0.809em auto;
+ height: 45px;
+ width: 45px;
+ background-color: #2980B9;
+ padding: 5px;
+ border-radius: 100%
+}
+
+.wy-side-nav-search>a,
+.wy-side-nav-search .wy-dropdown>a {
+ color: #fcfcfc;
+ font-size: 100%;
+ font-weight: bold;
+ display: inline-block;
+ padding: 4px 6px;
+ margin-bottom: 0.809em
+}
+
+.wy-side-nav-search>a:hover,
+.wy-side-nav-search .wy-dropdown>a:hover {
+ background: rgba(255, 255, 255, 0.1)
+}
+
+.wy-side-nav-search>a img.logo,
+.wy-side-nav-search .wy-dropdown>a img.logo {
+ display: block;
+ margin: 0 auto;
+ height: auto;
+ width: auto;
+ border-radius: 0;
+ max-width: 100%;
+ background: transparent
+}
+
+.wy-side-nav-search>a.icon img.logo,
+.wy-side-nav-search .wy-dropdown>a.icon img.logo {
+ margin-top: 0.85em
+}
+
+.wy-side-nav-search>div.version {
+ margin-top: -0.4045em;
+ margin-bottom: 0.809em;
+ font-weight: normal;
+ color: rgba(255, 255, 255, 0.3)
+}
+
+.wy-nav .wy-menu-vertical header {
+ color: #2980B9
+}
+
+.wy-nav .wy-menu-vertical a {
+ color: #b3b3b3
+}
+
+.wy-nav .wy-menu-vertical a:hover {
+ background-color: #2980B9;
+ color: #fff
+}
+
+[data-menu-wrap] {
+ -webkit-transition: all 0.2s ease-in;
+ -moz-transition: all 0.2s ease-in;
+ transition: all 0.2s ease-in;
+ position: absolute;
+ opacity: 1;
+ width: 100%;
+ opacity: 0
+}
+
+[data-menu-wrap].move-center {
+ left: 0;
+ right: auto;
+ opacity: 1
+}
+
+[data-menu-wrap].move-left {
+ right: auto;
+ left: -100%;
+ opacity: 0
+}
+
+[data-menu-wrap].move-right {
+ right: -100%;
+ left: auto;
+ opacity: 0
+}
+
+.wy-body-for-nav {
+ background: left repeat-y #fcfcfc;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);
+ background-size: 300px 1px
+}
+
+.wy-grid-for-nav {
+ position: absolute;
+ width: 100%;
+ height: 100%
+}
+
+.wy-nav-side {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ padding-bottom: 2em;
+ width: 300px;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ min-height: 100%;
+ background: #343131;
+ z-index: 200
+}
+
+.wy-side-scroll {
+ width: 320px;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ height: 100%
+}
+
+.wy-nav-top {
+ display: none;
+ background: #2980B9;
+ color: #fff;
+ padding: 0.4045em 0.809em;
+ position: relative;
+ line-height: 50px;
+ text-align: center;
+ font-size: 100%;
+ *zoom: 1
+}
+
+.wy-nav-top:before,
+.wy-nav-top:after {
+ display: table;
+ content: ""
+}
+
+.wy-nav-top:after {
+ clear: both
+}
+
+.wy-nav-top a {
+ color: #fff;
+ font-weight: bold
+}
+
+.wy-nav-top img {
+ margin-right: 12px;
+ height: 45px;
+ width: 45px;
+ background-color: #2980B9;
+ padding: 5px;
+ border-radius: 100%
+}
+
+.wy-nav-top i {
+ font-size: 30px;
+ float: left;
+ cursor: pointer;
+ padding-top: inherit
+}
+
+.wy-nav-content-wrap {
+ margin-left: 300px;
+ background: #fcfcfc;
+ min-height: 100%
+}
+
+.wy-nav-content {
+ padding: 1.618em 3.236em;
+ height: 100%;
+ max-width: 800px;
+ margin: auto
+}
+
+.wy-body-mask {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.2);
+ display: none;
+ z-index: 499
+}
+
+.wy-body-mask.on {
+ display: block
+}
+
+footer {
+ color: #999
+}
+
+footer p {
+ margin-bottom: 12px
+}
+
+footer span.commit code,
+footer span.commit .rst-content tt,
+.rst-content footer span.commit tt {
+ padding: 0px;
+ font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace;
+ font-size: 1em;
+ background: none;
+ border: none;
+ color: #999
+}
+
+.rst-footer-buttons {
+ *zoom: 1
+}
+
+.rst-footer-buttons:before,
+.rst-footer-buttons:after {
+ display: table;
+ content: ""
+}
+
+.rst-footer-buttons:after {
+ clear: both
+}
+
+#search-results .search li {
+ margin-bottom: 24px;
+ border-bottom: solid 1px #e1e4e5;
+ padding-bottom: 24px
+}
+
+#search-results .search li:first-child {
+ border-top: solid 1px #e1e4e5;
+ padding-top: 24px
+}
+
+#search-results .search li a {
+ font-size: 120%;
+ margin-bottom: 12px;
+ display: inline-block
+}
+
+#search-results .context {
+ color: gray;
+ font-size: 90%
+}
+
+@media screen and (max-width: 768px) {
+ .wy-body-for-nav {
+ background: #fcfcfc
+ }
+
+ .wy-nav-top {
+ display: block
+ }
+
+ .wy-nav-side {
+ left: -300px
+ }
+
+ .wy-nav-side.shift {
+ width: 85%;
+ left: 0
+ }
+
+ .wy-side-scroll {
+ width: auto
+ }
+
+ .wy-side-nav-search {
+ width: auto
+ }
+
+ .wy-menu.wy-menu-vertical {
+ width: auto
+ }
+
+ .wy-nav-content-wrap {
+ margin-left: 0
+ }
+
+ .wy-nav-content-wrap .wy-nav-content {
+ padding: 1.618em
+ }
+
+ .wy-nav-content-wrap.shift {
+ position: fixed;
+ min-width: 100%;
+ left: 85%;
+ top: 0;
+ height: 100%;
+ overflow: hidden
+ }
+}
+
+@media screen and (min-width: 1400px) {
+ .wy-nav-content-wrap {
+ background: rgba(0, 0, 0, 0.05)
+ }
+
+ .wy-nav-content {
+ margin: 0;
+ background: #fcfcfc
+ }
+}
+
+@media print {
+
+ .rst-versions,
+ footer,
+ .wy-nav-side {
+ display: none
+ }
+
+ .wy-nav-content-wrap {
+ margin-left: 0
+ }
+}
+
+.rst-versions {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 300px;
+ color: #fcfcfc;
+ background: #1f1d1d;
+ border-top: solid 10px #343131;
+ font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
+ z-index: 400
+}
+
+.rst-versions a {
+ color: #2980B9;
+ text-decoration: none
+}
+
+.rst-versions .rst-badge-small {
+ display: none
+}
+
+.rst-versions .rst-current-version {
+ padding: 12px;
+ background-color: #272525;
+ display: block;
+ text-align: right;
+ font-size: 90%;
+ cursor: pointer;
+ color: #27AE60;
+ *zoom: 1
+}
+
+.rst-versions .rst-current-version:before,
+.rst-versions .rst-current-version:after {
+ display: table;
+ content: ""
+}
+
+.rst-versions .rst-current-version:after {
+ clear: both
+}
+
+.rst-versions .rst-current-version .fa,
+.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,
+.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,
+.rst-versions .rst-current-version .rst-content .admonition-title,
+.rst-content .rst-versions .rst-current-version .admonition-title,
+.rst-versions .rst-current-version .rst-content h1 .headerlink,
+.rst-content h1 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content h2 .headerlink,
+.rst-content h2 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content h3 .headerlink,
+.rst-content h3 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content h4 .headerlink,
+.rst-content h4 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content h5 .headerlink,
+.rst-content h5 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content h6 .headerlink,
+.rst-content h6 .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content dl dt .headerlink,
+.rst-content dl dt .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content p.caption .headerlink,
+.rst-content p.caption .rst-versions .rst-current-version .headerlink,
+.rst-versions .rst-current-version .rst-content tt.download span:first-child,
+.rst-content tt.download .rst-versions .rst-current-version span:first-child,
+.rst-versions .rst-current-version .rst-content code.download span:first-child,
+.rst-content code.download .rst-versions .rst-current-version span:first-child,
+.rst-versions .rst-current-version .icon {
+ color: #fcfcfc
+}
+
+.rst-versions .rst-current-version .fa-book,
+.rst-versions .rst-current-version .icon-book {
+ float: left
+}
+
+.rst-versions .rst-current-version .icon-book {
+ float: left
+}
+
+.rst-versions .rst-current-version.rst-out-of-date {
+ background-color: #E74C3C;
+ color: #fff
+}
+
+.rst-versions .rst-current-version.rst-active-old-version {
+ background-color: #F1C40F;
+ color: #000
+}
+
+.rst-versions.shift-up .rst-other-versions {
+ display: block
+}
+
+.rst-versions .rst-other-versions {
+ font-size: 90%;
+ padding: 12px;
+ color: gray;
+ display: none
+}
+
+.rst-versions .rst-other-versions hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ margin: 20px 0;
+ padding: 0;
+ border-top: solid 1px #413d3d
+}
+
+.rst-versions .rst-other-versions dd {
+ display: inline-block;
+ margin: 0
+}
+
+.rst-versions .rst-other-versions dd a {
+ display: inline-block;
+ padding: 6px;
+ color: #fcfcfc
+}
+
+.rst-versions.rst-badge {
+ width: auto;
+ bottom: 20px;
+ right: 20px;
+ left: auto;
+ border: none;
+ max-width: 300px
+}
+
+.rst-versions.rst-badge .icon-book {
+ float: none
+}
+
+.rst-versions.rst-badge .fa-book,
+.rst-versions.rst-badge .icon-book {
+ float: none
+}
+
+.rst-versions.rst-badge.shift-up .rst-current-version {
+ text-align: right
+}
+
+.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,
+.rst-versions.rst-badge.shift-up .rst-current-version .icon-book {
+ float: left
+}
+
+.rst-versions.rst-badge.shift-up .rst-current-version .icon-book {
+ float: left
+}
+
+.rst-versions.rst-badge .rst-current-version {
+ width: auto;
+ height: 30px;
+ line-height: 30px;
+ padding: 0 6px;
+ display: block;
+ text-align: center
+}
+
+@media screen and (max-width: 768px) {
+ .rst-versions {
+ width: 85%;
+ display: none
+ }
+
+ .rst-versions.shift {
+ display: block
+ }
+
+ img {
+ width: 100%;
+ height: auto
+ }
+}
+
+.rst-content img {
+ max-width: 100%;
+ height: auto !important
+}
+
+.rst-content div.figure {
+ margin-bottom: 24px
+}
+
+.rst-content div.figure p.caption {
+ font-style: italic
+}
+
+.rst-content div.figure.align-center {
+ text-align: center
+}
+
+.rst-content .section>img,
+.rst-content .section>a>img {
+ margin-bottom: 24px
+}
+
+.rst-content blockquote {
+ margin-left: 24px;
+ line-height: 24px;
+ margin-bottom: 24px
+}
+
+.rst-content .note .last,
+.rst-content .attention .last,
+.rst-content .caution .last,
+.rst-content .danger .last,
+.rst-content .error .last,
+.rst-content .hint .last,
+.rst-content .important .last,
+.rst-content .tip .last,
+.rst-content .warning .last,
+.rst-content .seealso .last,
+.rst-content .admonition-todo .last {
+ margin-bottom: 0
+}
+
+.rst-content .admonition-title:before {
+ margin-right: 4px
+}
+
+.rst-content .admonition table {
+ border-color: rgba(0, 0, 0, 0.1)
+}
+
+.rst-content .admonition table td,
+.rst-content .admonition table th {
+ background: transparent !important;
+ border-color: rgba(0, 0, 0, 0.1) !important
+}
+
+.rst-content .section ol.loweralpha,
+.rst-content .section ol.loweralpha li {
+ list-style: lower-alpha
+}
+
+.rst-content .section ol.upperalpha,
+.rst-content .section ol.upperalpha li {
+ list-style: upper-alpha
+}
+
+.rst-content .section ol p,
+.rst-content .section ul p {
+ margin-bottom: 12px
+}
+
+.rst-content .line-block {
+ margin-left: 24px
+}
+
+.rst-content .topic-title {
+ font-weight: bold;
+ margin-bottom: 12px
+}
+
+.rst-content .toc-backref {
+ color: #404040
+}
+
+.rst-content .align-right {
+ float: right;
+ margin: 0px 0px 24px 24px
+}
+
+.rst-content .align-left {
+ float: left;
+ margin: 0px 24px 24px 0px
+}
+
+.rst-content .align-center {
+ margin: auto;
+ display: block
+}
+
+.rst-content h1 .headerlink,
+.rst-content h2 .headerlink,
+.rst-content .toctree-wrapper p.caption .headerlink,
+.rst-content h3 .headerlink,
+.rst-content h4 .headerlink,
+.rst-content h5 .headerlink,
+.rst-content h6 .headerlink,
+.rst-content dl dt .headerlink,
+.rst-content p.caption .headerlink {
+ display: none;
+ visibility: hidden;
+ font-size: 14px
+}
+
+.rst-content h1 .headerlink:after,
+.rst-content h2 .headerlink:after,
+.rst-content .toctree-wrapper p.caption .headerlink:after,
+.rst-content h3 .headerlink:after,
+.rst-content h4 .headerlink:after,
+.rst-content h5 .headerlink:after,
+.rst-content h6 .headerlink:after,
+.rst-content dl dt .headerlink:after,
+.rst-content p.caption .headerlink:after {
+ visibility: visible;
+ content: "";
+ font-family: FontAwesome;
+ display: inline-block
+}
+
+.rst-content h1:hover .headerlink,
+.rst-content h2:hover .headerlink,
+.rst-content .toctree-wrapper p.caption:hover .headerlink,
+.rst-content h3:hover .headerlink,
+.rst-content h4:hover .headerlink,
+.rst-content h5:hover .headerlink,
+.rst-content h6:hover .headerlink,
+.rst-content dl dt:hover .headerlink,
+.rst-content p.caption:hover .headerlink {
+ display: inline-block
+}
+
+.rst-content .sidebar {
+ float: right;
+ width: 40%;
+ display: block;
+ margin: 0 0 24px 24px;
+ padding: 24px;
+ background: #f3f6f6;
+ border: solid 1px #e1e4e5
+}
+
+.rst-content .sidebar p,
+.rst-content .sidebar ul,
+.rst-content .sidebar dl {
+ font-size: 90%
+}
+
+.rst-content .sidebar .last {
+ margin-bottom: 0
+}
+
+.rst-content .sidebar .sidebar-title {
+ display: block;
+ font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif;
+ font-weight: bold;
+ background: #e1e4e5;
+ padding: 6px 12px;
+ margin: -24px;
+ margin-bottom: 24px;
+ font-size: 100%
+}
+
+.rst-content .highlighted {
+ background: #F1C40F;
+ display: inline-block;
+ font-weight: bold;
+ padding: 0 6px
+}
+
+.rst-content .footnote-reference,
+.rst-content .citation-reference {
+ vertical-align: super;
+ font-size: 90%
+}
+
+.rst-content table.docutils.citation,
+.rst-content table.docutils.footnote {
+ background: none;
+ border: none;
+ color: #999
+}
+
+.rst-content table.docutils.citation td,
+.rst-content table.docutils.citation tr,
+.rst-content table.docutils.footnote td,
+.rst-content table.docutils.footnote tr {
+ border: none;
+ background-color: transparent !important;
+ white-space: normal
+}
+
+.rst-content table.docutils.citation td.label,
+.rst-content table.docutils.footnote td.label {
+ padding-left: 0;
+ padding-right: 0;
+ vertical-align: top
+}
+
+.rst-content table.docutils.citation tt,
+.rst-content table.docutils.citation code,
+.rst-content table.docutils.footnote tt,
+.rst-content table.docutils.footnote code {
+ color: #555
+}
+
+.rst-content table.field-list {
+ border: none
+}
+
+.rst-content table.field-list td {
+ border: none;
+ padding-top: 5px
+}
+
+.rst-content table.field-list td>strong {
+ display: inline-block;
+ margin-top: 3px
+}
+
+.rst-content table.field-list .field-name {
+ padding-right: 10px;
+ text-align: left;
+ white-space: nowrap
+}
+
+.rst-content table.field-list .field-body {
+ text-align: left;
+ padding-left: 0
+}
+
+.rst-content tt,
+.rst-content tt,
+.rst-content code {
+ color: #000;
+ padding: 2px 5px
+}
+
+.rst-content tt big,
+.rst-content tt em,
+.rst-content tt big,
+.rst-content code big,
+.rst-content tt em,
+.rst-content code em {
+ font-size: 100% !important;
+ line-height: normal
+}
+
+.rst-content tt.literal,
+.rst-content tt.literal,
+.rst-content code.literal {
+ color: #E74C3C
+}
+
+.rst-content tt.xref,
+a .rst-content tt,
+.rst-content tt.xref,
+.rst-content code.xref,
+a .rst-content tt,
+a .rst-content code {
+ font-weight: bold;
+ color: #404040
+}
+
+.rst-content a tt,
+.rst-content a tt,
+.rst-content a code {
+ color: #2980B9
+}
+
+.rst-content dl {
+ margin-bottom: 24px
+}
+
+.rst-content dl dt {
+ font-weight: bold
+}
+
+.rst-content dl p,
+.rst-content dl table,
+.rst-content dl ul,
+.rst-content dl ol {
+ margin-bottom: 12px !important
+}
+
+.rst-content dl dd {
+ margin: 0 0 12px 24px
+}
+
+.rst-content dl:not(.docutils) {
+ margin-bottom: 24px
+}
+
+.rst-content dl:not(.docutils) dt {
+ display: inline-block;
+ margin: 6px 0;
+ font-size: 90%;
+ line-height: normal;
+ background: #e7f2fa;
+ color: #2980B9;
+ border-top: solid 3px #6ab0de;
+ padding: 6px;
+ position: relative
+}
+
+.rst-content dl:not(.docutils) dt:before {
+ color: #6ab0de
+}
+
+.rst-content dl:not(.docutils) dt .headerlink {
+ color: #404040;
+ font-size: 100% !important
+}
+
+.rst-content dl:not(.docutils) dl dt {
+ margin-bottom: 6px;
+ border: none;
+ border-left: solid 3px #ccc;
+ background: #f0f0f0;
+ color: #555
+}
+
+.rst-content dl:not(.docutils) dl dt .headerlink {
+ color: #404040;
+ font-size: 100% !important
+}
+
+.rst-content dl:not(.docutils) dt:first-child {
+ margin-top: 0
+}
+
+.rst-content dl:not(.docutils) tt,
+.rst-content dl:not(.docutils) tt,
+.rst-content dl:not(.docutils) code {
+ font-weight: bold
+}
+
+.rst-content dl:not(.docutils) tt.descname,
+.rst-content dl:not(.docutils) tt.descclassname,
+.rst-content dl:not(.docutils) tt.descname,
+.rst-content dl:not(.docutils) code.descname,
+.rst-content dl:not(.docutils) tt.descclassname,
+.rst-content dl:not(.docutils) code.descclassname {
+ background-color: transparent;
+ border: none;
+ padding: 0;
+ font-size: 100% !important
+}
+
+.rst-content dl:not(.docutils) tt.descname,
+.rst-content dl:not(.docutils) tt.descname,
+.rst-content dl:not(.docutils) code.descname {
+ font-weight: bold
+}
+
+.rst-content dl:not(.docutils) .optional {
+ display: inline-block;
+ padding: 0 4px;
+ color: #000;
+ font-weight: bold
+}
+
+.rst-content dl:not(.docutils) .property {
+ display: inline-block;
+ padding-right: 8px
+}
+
+.rst-content .viewcode-link,
+.rst-content .viewcode-back {
+ display: inline-block;
+ color: #27AE60;
+ font-size: 80%;
+ padding-left: 24px
+}
+
+.rst-content .viewcode-back {
+ display: block;
+ float: right
+}
+
+.rst-content p.rubric {
+ margin-bottom: 12px;
+ font-weight: bold
+}
+
+.rst-content tt.download,
+.rst-content code.download {
+ background: inherit;
+ padding: inherit;
+ font-family: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: inherit;
+ white-space: inherit
+}
+
+.rst-content tt.download span:first-child:before,
+.rst-content code.download span:first-child:before {
+ margin-right: 4px
+}
+
+@media screen and (max-width: 480px) {
+ .rst-content .sidebar {
+ width: 100%
+ }
+}
+
+span[id*='MathJax-Span'] {
+ color: #404040
+}
+
+.math {
+ text-align: center
+}
+
+@font-face {
+ font-family: "Inconsolata";
+ font-style: normal;
+ font-weight: 400;
+ src: local("Inconsolata"), local("Inconsolata-Regular"), url(../fonts/Inconsolata-Regular.ttf) format("truetype")
+}
+
+@font-face {
+ font-family: "Inconsolata";
+ font-style: normal;
+ font-weight: 700;
+ src: local("Inconsolata Bold"), local("Inconsolata-Bold"), url(../fonts/Inconsolata-Bold.ttf) format("truetype")
+}
+
+@font-face {
+ font-family: "Lato";
+ font-style: normal;
+ font-weight: 400;
+ src: local("Lato Regular"), local("Lato-Regular"), url(../fonts/Lato-Regular.ttf) format("truetype")
+}
+
+@font-face {
+ font-family: "Lato";
+ font-style: normal;
+ font-weight: 700;
+ src: local("Lato Bold"), local("Lato-Bold"), url(../fonts/Lato-Bold.ttf) format("truetype")
+}
+
+@font-face {
+ font-family: "Roboto Slab";
+ font-style: normal;
+ font-weight: 400;
+ src: local("Roboto Slab Regular"), local("RobotoSlab-Regular"), url(../fonts/RobotoSlab-Regular.ttf) format("truetype")
+}
+
+@font-face {
+ font-family: "Roboto Slab";
+ font-style: normal;
+ font-weight: 700;
+ src: local("Roboto Slab Bold"), local("RobotoSlab-Bold"), url(../fonts/RobotoSlab-Bold.ttf) format("truetype")
+}
+
+/*# sourceMappingURL=theme.css.map */
\ No newline at end of file
diff --git a/docs/themes/sphinx_rtd_theme/static/css/theme.css.map b/docs/themes/sphinx_rtd_theme/static/css/theme.css.map
index 96cc9d2..e934780 100644
--- a/docs/themes/sphinx_rtd_theme/static/css/theme.css.map
+++ b/docs/themes/sphinx_rtd_theme/static/css/theme.css.map
@@ -1,4 +1,4 @@
-{
+ {
"version": 3,
"mappings": "CACE,AAAE,ECQI,iBAAoB,EDPJ,SAAU,ECY1B,cAAiB,EDZD,SAAU,EC2B1B,SAAY,ED3BI,SAAU,EEFlC,uEAAiF,EAC/E,MAAO,EAAE,IAAK,EAEhB,iBAAoB,EAClB,MAAO,EAAE,WAAY,EACrB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,AAAC,EAEV,oBAAqB,EACnB,MAAO,EAAE,GAAI,EAEf,OAAQ,EACN,MAAO,EAAE,GAAI,EAEf,AAAC,EDLO,iBAAoB,ECMd,SAAU,EDDhB,cAAiB,ECCX,SAAU,EDchB,SAAY,ECdN,SAAU,EAExB,GAAI,EACF,QAAS,EAAE,GAAI,EACf,uBAAwB,EAAE,GAAI,EAC9B,mBAAoB,EAAE,GAAI,EAE5B,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,eAAiB,EACf,MAAO,EAAE,AAAC,EAEZ,UAAW,EACT,YAAa,EAAE,SAAU,EAE3B,OAAS,EACP,UAAW,EAAE,GAAI,EAEnB,SAAU,EACR,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,SAAU,EAAE,KAAM,EAGpB,EAAG,EACD,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,cAAe,EAAE,GAAI,EAEvB,GAAI,EACF,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAI,EACX,SAAU,EAAE,KAAM,EAClB,UAAW,EAAE,GAAI,EAEnB,kDAAoB,EAClB,UAAW,EAAE,cAAS,EACtB,WAAY,EAAE,sBAAa,EAC3B,QAAS,EAAE,EAAG,EAEhB,EAAG,EACD,UAAW,EAAE,EAAG,EAElB,AAAC,EACC,KAAM,EAAE,GAAI,EAEd,eAAiB,EACf,MAAO,EAAE,CAAE,EACX,MAAO,EAAE,GAAI,EAEf,IAAK,EACH,QAAS,EAAE,EAAG,EAEhB,MAAQ,EACN,QAAS,EAAE,EAAG,EACd,UAAW,EAAE,AAAC,EACd,OAAQ,EAAE,OAAQ,EAClB,aAAc,EAAE,OAAQ,EAE1B,EAAG,EACD,EAAG,EAAE,KAAM,EAEb,EAAG,EACD,KAAM,EAAE,MAAO,EAEjB,OAAU,EACR,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EACV,SAAU,EAAE,GAAI,EAChB,eAAgB,EAAE,GAAI,EAExB,CAAE,EACA,SAAU,EAAE,GAAI,EAElB,CAAE,EACA,KAAM,EAAE,AAAC,EAEX,EAAG,EACD,KAAM,EAAE,AAAC,EACT,qBAAsB,EAAE,MAAO,EAC/B,aAAc,EAAE,KAAM,EACtB,QAAS,EAAE,GAAI,EAEjB,aAAc,EACZ,OAAQ,EAAE,KAAM,EAElB,KAAM,EACJ,KAAM,EAAE,AAAC,EAEX,GAAI,EACF,KAAM,EAAE,AAAC,EAEX,OAAQ,EACN,KAAM,EAAE,AAAC,EACT,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,IAAK,EACH,KAAM,EAAE,MAAO,EAEjB,KAAM,EACJ,KAAM,EAAE,AAAC,EACT,WAAY,EAAE,GAAI,EAClB,MAAO,EAAE,AAAC,EACV,UAAW,EAAE,KAAM,EAErB,2BAA+B,EAC7B,QAAS,EAAE,GAAI,EACf,KAAM,EAAE,AAAC,EACT,aAAc,EAAE,OAAQ,EACxB,cAAe,EAAE,KAAM,EAEzB,WAAa,EACX,UAAW,EAAE,KAAM,EAErB,mEAAuE,EACrE,KAAM,EAAE,MAAO,EACf,iBAAkB,EAAE,KAAM,EAC1B,QAAS,EAAE,MAAO,EAEpB,+BAAiC,EAC/B,KAAM,EAAE,MAAO,EAEjB,yCAA2C,EACzC,SAAU,EAAE,SAAU,EACtB,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,GAAI,EACZ,MAAO,EAAE,GAAI,EAEf,mBAAoB,EAClB,iBAAkB,EAAE,QAAS,EAC7B,cAAe,EAAE,UAAW,EAC5B,iBAAkB,EAAE,UAAW,EAC/B,SAAU,EAAE,UAAW,EAEzB,iGAAmG,EACjG,iBAAkB,EAAE,GAAI,EAE1B,+CAAiD,EAC/C,KAAM,EAAE,AAAC,EACT,MAAO,EAAE,AAAC,EAEZ,OAAQ,EACN,OAAQ,EAAE,GAAI,EACd,aAAc,EAAE,EAAG,EACnB,KAAM,EAAE,OAAQ,EAElB,IAAK,EACH,cAAe,EAAE,OAAQ,EACzB,aAAc,EAAE,AAAC,EAEnB,CAAE,EACA,aAAc,EAAE,EAAG,EAErB,WAAY,EACV,KAAM,EAAE,MAAO,EACf,SAAU,EAAE,GAAI,EAChB,IAAK,EAAE,GAAK,EACZ,MAAO,EAAE,MAAO,EAElB,EAAG,EACD,MAAO,EAAE,IAAK,EACd,KAAM,EAAE,AAAC,EACT,UAAW,EAAE,KAAM,EACnB,OAAQ,EAAE,KAAM,EAChB,eAAgB,EAAE,UAAW,EAC7B,gBAAiB,EAAE,QAAS,EAC5B,SAAU,EAAE,GAAI,EAChB,QAAS,EAAE,EAAG,EACd,WAAY,EAAE,AAAC,EAEjB,KAAM,EACJ,MAAO,EAAE,GAAI,EAEf,MAAO,EACL,MAAO,EAAE,cAAe,EACxB,SAAU,EAAE,KAAM,EAEpB,cAAe,EACb,KAAM,EAAE,AAAC,EACT,GAAI,EAAE,YAAa,EACnB,KAAM,EAAE,EAAG,EACX,KAAM,EAAE,GAAI,EACZ,OAAQ,EAAE,KAAM,EAChB,MAAO,EAAE,AAAC,EACV,OAAQ,EAAE,OAAQ,EAClB,IAAK,EAAE,EAAG,EAEZ,+DAAiE,EAC/D,GAAI,EAAE,GAAI,EACV,KAAM,EAAE,GAAI,EACZ,KAAM,EAAE,AAAC,EACT,OAAQ,EAAE,MAAO,EACjB,OAAQ,EAAE,KAAM,EAChB,IAAK,EAAE,GAAI,EAEb,SAAU,EACR,SAAU,EAAE,KAAM,EAEpB,QAAS,EACP,OAAQ,EAAE,OAAQ,EAEpB,QAAU,EACR,QAAS,EAAE,GAAI,EAEjB,WAAY,EACV,gBAAmB,EACjB,SAAU,EAAE,cAAe,EAC7B,AAAC,EACC,SAAU,EAAE,cAAe,EAC3B,UAAW,EAAE,cAAe,EAC5B,KAAM,EAAE,cAAe,EACvB,SAAU,EAAE,cAAe,EAC7B,UAAY,EACV,cAAe,EAAE,QAAS,EAC5B,0DAA6D,EAC3D,MAAO,EAAE,CAAE,EACb,aAAe,EACb,gBAAiB,EAAE,IAAK,EAC1B,IAAK,EACH,MAAO,EAAE,iBAAkB,EAC7B,KAAO,EACL,gBAAiB,EAAE,IAAK,EAC1B,EAAG,EACD,QAAS,EAAE,cAAe,QAE1B,KAAM,EAAE,IAAK,EAEf,8CAAS,EACP,MAAO,EAAE,AAAC,EACV,KAAM,EAAE,AAAC,EACX,4CAAM,EACJ,eAAgB,EAAE,IAAK,GChM3B,ykDAAY,EACV,qBAAsB,EAAE,UAAW,EAqDrC,QAAS,EARP,IAAK,EAAE,AAAC,EACR,+BAAS,EAEP,MAAO,EAAE,IAAK,EACd,MAAO,EAAE,CAAE,EACb,cAAO,EACL,IAAK,EAAE,GAAI;;;GC1Gf,UAUC,CATC,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,+CAAgE,CACrE,GAAG,CAAE,sSAAmG,CAKxG,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CCTpB,kfAAmB,CACjB,OAAO,CAAE,YAAY,CACrB,IAAI,CAAE,uCAAuC,CAC7C,SAAS,CAAE,OAAO,CAClB,cAAc,CAAE,IAAI,CACpB,sBAAsB,CAAE,WAAW,CACnC,uBAAuB,CAAE,SAAS,CCLpC,MAAsB,CACpB,SAAS,CAAE,SAAS,CACpB,WAAW,CAAE,MAAS,CACtB,cAAc,CAAE,IAAI,CAEtB,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CACtC,MAAsB,CAAE,SAAS,CAAE,GAAG,CCVtC,MAAsB,CACpB,KAAK,CAAE,SAAW,CAClB,UAAU,CAAE,MAAM,CCDpB,MAAsB,CACpB,YAAY,CAAE,CAAC,CACf,WAAW,CCIU,SAAS,CDH9B,eAAe,CAAE,IAAI,CACrB,SAAK,CAAE,QAAQ,CAAE,QAAQ,CAE3B,MAAsB,CACpB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,UAAa,CACnB,KAAK,CCHgB,SAAS,CDI9B,GAAG,CAAE,SAAU,CACf,UAAU,CAAE,MAAM,CAClB,YAAuB,CACrB,IAAI,CAAE,UAA0B,CEbpC,UAA0B,CACxB,OAAO,CAAE,gBAAgB,CACzB,MAAM,CAAE,iBAA4B,CACpC,aAAa,CAAE,IAAI,CAGrB,WAAY,CAAE,KAAK,CAAE,KAAK,CAC1B,UAAW,CAAE,KAAK,CAAE,IAAI,CAGtB,kpBAAY,CAAE,YAAY,CAAE,IAAI,CAChC,kqBAAa,CAAE,WAAW,CAAE,IAAI,CCXlC,QAAwB,CACtB,iBAAiB,CAAE,0BAA0B,CACrC,SAAS,CAAE,0BAA0B,CAG/C,0BASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,EAIrC,kBASC,CARC,EAAG,CACD,iBAAiB,CAAE,YAAY,CACvB,SAAS,CAAE,YAAY,CAEjC,IAAK,CACH,iBAAiB,CAAE,cAAc,CACzB,SAAS,CAAE,cAAc,ECvBrC,aAA8B,CCU5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,aAAgB,CAC/B,aAAa,CAAE,aAAgB,CAC3B,SAAS,CAAE,aAAgB,CDZrC,cAA8B,CCS5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDXrC,cAA8B,CCQ5B,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,cAAgB,CAC/B,aAAa,CAAE,cAAgB,CAC3B,SAAS,CAAE,cAAgB,CDTrC,mBAAmC,CCajC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDfzC,iBAAmC,CCYjC,MAAM,CAAE,wDAAmE,CAC3E,iBAAiB,CAAE,YAAoB,CACnC,aAAa,CAAE,YAAoB,CAC/B,SAAS,CAAE,YAAoB,CDVzC,+GAIuC,CACrC,MAAM,CAAE,IAAI,CEfd,SAAyB,CACvB,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CACrB,KAAK,CAAE,GAAG,CACV,MAAM,CAAE,GAAG,CACX,WAAW,CAAE,GAAG,CAChB,cAAc,CAAE,MAAM,CAExB,yBAAyD,CACvD,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,MAAM,CAEpB,YAA4B,CAAE,WAAW,CAAE,OAAO,CAClD,YAA4B,CAAE,SAAS,CAAE,GAAG,CAC5C,WAA2B,CAAE,KAAK,CLXZ,IAAI,CML1B,gBAAgC,CAAE,OAAO,CNwP1B,GAAO,CMvPtB,gBAAgC,CAAE,OAAO,CNkV1B,GAAO,CMjVtB,qCAAiC,CAAE,OAAO,CNyZ1B,GAAO,CMxZvB,qBAAqC,CAAE,OAAO,CN2K1B,GAAO,CM1K3B,gBAAgC,CAAE,OAAO,CNqQ1B,GAAO,CMpQtB,eAA+B,CAAE,OAAO,CNkc1B,GAAO,CMjcrB,iBAAiC,CAAE,OAAO,CNsc1B,GAAO,CMrcvB,eAA+B,CAAE,OAAO,CN0gB1B,GAAO,CMzgBrB,eAA+B,CAAE,OAAO,CN+M1B,GAAO,CM9MrB,mBAAmC,CAAE,OAAO,CN8d1B,GAAO,CM7dzB,aAA6B,CAAE,OAAO,CN4d1B,GAAO,CM3dnB,kBAAkC,CAAE,OAAO,CN6d1B,GAAO,CM5dxB,gBAAgC,CAAE,OAAO,CN+F1B,GAAO,CM9FtB,mDAEgC,CAAE,OAAO,CNge1B,GAAO,CM/dtB,sBAAsC,CAAE,OAAO,CN6Y1B,GAAO,CM5Y5B,uBAAuC,CAAE,OAAO,CN2Y1B,GAAO,CM1Y7B,oBAAoC,CAAE,OAAO,CNqW1B,GAAO,CMpW1B,iBAAiC,CAAE,OAAO,CNwZ1B,GAAO,CMvZvB,8BAC8B,CAAE,OAAO,CNmH1B,GAAO,CMlHpB,kBAAkC,CAAE,OAAO,CNoe1B,GAAO,CMnexB,iCAA+B,CAAE,OAAO,CNqP1B,GAAO,CMpPrB,iBAAiC,CAAE,OAAO,CNmL1B,GAAO,CMlLvB,kBAAkC,CAAE,OAAO,CNqG1B,GAAO,CMpGxB,eAA+B,CAAE,OAAO,CNqX1B,GAAO,CMpXrB,uHAAmC,CAAE,OAAO,CNyI1B,GAAO,CMxIzB,8BAA8C,CAAE,OAAO,CNG1B,GAAO,CMFpC,4BAA4C,CAAE,OAAO,CNK1B,GAAO,CMJlC,gBAAgC,CAAE,OAAO,CNmP1B,GAAO,CMlPtB,wBAAwC,CAAE,OAAO,CNkV1B,GAAO,CMjV9B,yCACiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,kBAAkC,CAAE,OAAO,CNoW1B,GAAO,CMnWxB,mBAAmC,CAAE,OAAO,CNiR1B,GAAO,CMhRzB,eAA+B,CAAE,OAAO,CNoR1B,GAAO,CMnRrB,eAA+B,CAAE,OAAO,CNsL1B,GAAO,CMrLrB,qBAAqC,CAAE,OAAO,CNkO1B,GAAO,CMjO3B,qBAAqC,CAAE,OAAO,CNkf1B,GAAO,CMjf3B,sBAAsC,CAAE,OAAO,CNgf1B,GAAO,CM/e5B,oBAAoC,CAAE,OAAO,CNif1B,GAAO,CMhf1B,iBAAiC,CAAE,OAAO,CNiV1B,GAAO,CMhVvB,kBAAkC,CAAE,OAAO,CNU1B,GAAO,CMTxB,cAA8B,CAAE,OAAO,CNkb1B,GAAO,CMjbpB,eAA+B,CAAE,OAAO,CNkb1B,GAAO,CMjbrB,iCAA+B,CAAE,OAAO,CNyB1B,GAAO,CMxBrB,mBAAmC,CAAE,OAAO,CNyB1B,GAAO,CMxBzB,gBAAgC,CAAE,OAAO,CNwU1B,GAAO,CMvUtB,iBAAiC,CAAE,OAAO,CNqC1B,GAAO,CMpCvB,eAA+B,CAAE,OAAO,CNoL1B,GAAO,CMnLrB,eAA+B,CAAE,OAAO,CNiB1B,GAAO,CMhBrB,iBAAiC,CAAE,OAAO,CNqO1B,GAAO,CMpOvB,sBAAsC,CAAE,OAAO,CN+a1B,GAAO,CM9a5B,qBAAqC,CAAE,OAAO,CN+a1B,GAAO,CM9a3B,qBAAqC,CAAE,OAAO,CN3C1B,GAAO,CM4C3B,uBAAuC,CAAE,OAAO,CN9C1B,GAAO,CM+C7B,sBAAsC,CAAE,OAAO,CN5C1B,GAAO,CM6C5B,wBAAwC,CAAE,OAAO,CN/C1B,GAAO,CMgD9B,eAA+B,CAAE,OAAO,CNwP1B,GAAO,CMvPrB,oCACkC,CAAE,OAAO,CN0R1B,GAAO,CMzRxB,iBAAiC,CAAE,OAAO,CNoN1B,GAAO,CMnNvB,uBAAuC,CAAE,OAAO,CNqd1B,GAAO,CMpd7B,sDAEoC,CAAE,OAAO,CNsS1B,GAAO,CMrS1B,iBAAiC,CAAE,OAAO,CN+R1B,GAAO,CM9RvB,qBAAqC,CAAE,OAAO,CN+P1B,GAAO,CM9P3B,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,eAA+B,CAAE,OAAO,CN4a1B,GAAO,CM3arB,0CAC0C,CAAE,OAAO,CN4R1B,GAAO,CM3RhC,yBAAyC,CAAE,OAAO,CN2V1B,GAAO,CM1V/B,yBAAyC,CAAE,OAAO,CNqC1B,GAAO,CMpC/B,iBAAiC,CAAE,OAAO,CNlC1B,GAAO,CMmCvB,wBAAwC,CAAE,OAAO,CNmY1B,GAAO,CMlY9B,wBAAwC,CAAE,OAAO,CNkH1B,GAAO,CMjH9B,mBAAmC,CAAE,OAAO,CN9B1B,GAAO,CM+BzB,eAA+B,CAAE,OAAO,CNgS1B,GAAO,CM/RrB,gBAAgC,CAAE,OAAO,CN+Q1B,GAAO,CM9QtB,eAA+B,CAAE,OAAO,CNiY1B,GAAO,CMhYrB,kBAAkC,CAAE,OAAO,CNqJ1B,GAAO,CMpJxB,uBAAuC,CAAE,OAAO,CN6G1B,GAAO,CM5G7B,uBAAuC,CAAE,OAAO,CN4X1B,GAAO,CM3X7B,gBAAgC,CAAE,OAAO,CNoF1B,GAAO,CMnFtB,uBAAuC,CAAE,OAAO,CN+B1B,GAAO,CM9B7B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,sBAAsC,CAAE,OAAO,CN4R1B,GAAO,CM3R5B,uBAAuC,CAAE,OAAO,CNkP1B,GAAO,CMjP7B,8FAAuC,CAAE,OAAO,CNsZ1B,GAAO,CMrZ7B,+FAAuC,CAAE,OAAO,CNiB1B,GAAO,CMhB7B,0BAA0C,CAAE,OAAO,CNiS1B,GAAO,CMhShC,sBAAsC,CAAE,OAAO,CNuL1B,GAAO,CMtL5B,qBAAqC,CAAE,OAAO,CNuD1B,GAAO,CMtD3B,yBAAyC,CAAE,OAAO,CNkZ1B,GAAO,CMjZ/B,yBAAyC,CAAE,OAAO,CNa1B,GAAO,CMZ/B,cAA8B,CAAE,OAAO,CNhD1B,GAAO,CMiDpB,qBAAqC,CAAE,OAAO,CN5D1B,GAAO,CM6D3B,sBAAsC,CAAE,OAAO,CN5D1B,GAAO,CM6D5B,mBAAmC,CAAE,OAAO,CN5D1B,GAAO,CM6DzB,qBAAqC,CAAE,OAAO,CNhE1B,GAAO,CMiE3B,wCACgC,CAAE,OAAO,CNyT1B,GAAO,CMxTtB,iBAAiC,CAAE,OAAO,CN+E1B,GAAO,CM9EvB,mBAAmC,CAAE,OAAO,CNuC1B,GAAO,CMtCzB,eAA+B,CAAE,OAAO,CNyQ1B,GAAO,CMxQrB,gBAAgC,CAAE,OAAO,CN+N1B,GAAO,CM9NtB,mBAAmC,CAAE,OAAO,CN/D1B,GAAO,CMgEzB,gNAA6C,CAAE,OAAO,CNwE1B,GAAO,CMvEnC,eAA+B,CAAE,OAAO,CNmI1B,GAAO,CMlIrB,eAA+B,CAAE,OAAO,CNqL1B,GAAO,CMpLrB,iCAA+B,CAAE,OAAO,CNyG1B,GAAO,CMxGrB,cAA8B,CAAE,OAAO,CNyE1B,GAAO,CMxEpB,oBAAoC,CAAE,OAAO,CNyE1B,GAAO,CMxE1B,kDAC+C,CAAE,OAAO,CNkE1B,GAAO,CMjErC,gBAAgC,CAAE,OAAO,CNyP1B,GAAO,CMxPtB,mBAAmC,CAAE,OAAO,CNlC1B,GAAO,CMmCzB,iBAAiC,CAAE,OAAO,CN0Q1B,GAAO,CMzQvB,kBAAkC,CAAE,OAAO,CNmB1B,GAAO,CMlBxB,iBAAiC,CAAE,OAAO,CNqM1B,GAAO,CMpMvB,qBAAqC,CAAE,OAAO,CNH1B,GAAO,CMI3B,uBAAuC,CAAE,OAAO,CNP1B,GAAO,CMQ7B,kBAAkC,CAAE,OAAO,CNiR1B,GAAO,CMhRxB,wBAAwC,CAAE,OAAO,CN2S1B,GAAO,CM1S9B,iBAAiC,CAAE,OAAO,CNoG1B,GAAO,CMnGvB,sBAAsC,CAAE,OAAO,CNqG1B,GAAO,CMpG5B,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,mBAAmC,CAAE,OAAO,CNtF1B,GAAO,CMuFzB,2CACoC,CAAE,OAAO,CNhF1B,GAAO,CMiF1B,yBAAyC,CAAE,OAAO,CNkY1B,GAAO,CMjY/B,0BAA0C,CAAE,OAAO,CNyD1B,GAAO,CMxDhC,uBAAuC,CAAE,OAAO,CN/C1B,GAAO,CMgD7B,cAA8B,CAAE,OAAO,CNsJ1B,GAAO,CMrJpB,gCAC+B,CAAE,OAAO,CNA1B,GAAO,CMCrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNiW1B,GAAO,CMhW5B,wBAAwC,CAAE,OAAO,CN+V1B,GAAO,CM9V9B,oBAAoC,CAAE,OAAO,CN2T1B,GAAO,CM1T1B,kBAAkC,CAAE,OAAO,CN4H1B,GAAO,CM3HxB,mBAAmC,CAAE,OAAO,CN2R1B,GAAO,CM1RzB,0BAA0C,CAAE,OAAO,CNiK1B,GAAO,CMhKhC,qBAAqC,CAAE,OAAO,CNwV1B,GAAO,CMvV3B,wBAAwC,CAAE,OAAO,CNsC1B,GAAO,CMrC9B,kBAAkC,CAAE,OAAO,CNsR1B,GAAO,CMrRxB,iBAAiC,CAAE,OAAO,CNyW1B,GAAO,CMxWvB,wBAAwC,CAAE,OAAO,CNiG1B,GAAO,CMhG9B,iBAAiC,CAAE,OAAO,CNyX1B,GAAO,CMxXvB,kBAAkC,CAAE,OAAO,CN+I1B,GAAO,CM9IxB,gBAAgC,CAAE,OAAO,CN6M1B,GAAO,CM5MtB,mBAAmC,CAAE,OAAO,CN2S1B,GAAO,CM1SzB,qBAAqC,CAAE,OAAO,CNjF1B,GAAO,CMkF3B,uBAAuC,CAAE,OAAO,CN2M1B,GAAO,CM1M7B,kBAAkC,CAAE,OAAO,CNyW1B,GAAO,CMxWxB,mBAAmC,CAAE,OAAO,CNgC1B,GAAO,CM/BzB,qCAAiC,CAAE,OAAO,CNsF1B,GAAO,CMrFvB,iBAAiC,CAAE,OAAO,CN6W1B,GAAO,CM5WvB,sBAAsC,CAAE,OAAO,CNb1B,GAAO,CMc5B,cAA8B,CAAE,OAAO,CNmP1B,GAAO,CMlPpB,gBAAgC,CAAE,OAAO,CNoG1B,GAAO,CMnGtB,mBAAmC,CAAE,OAAO,CNpF1B,GAAO,CMqFzB,eAA+B,CAAE,OAAO,CN1G1B,GAAO,CM2GrB,sBAAsC,CAAE,OAAO,CN7D1B,GAAO,CM8D5B,uBAAuC,CAAE,OAAO,CN8F1B,GAAO,CM7F7B,sBAAsC,CAAE,OAAO,CN4F1B,GAAO,CM3F5B,oBAAoC,CAAE,OAAO,CN6F1B,GAAO,CM5F1B,sBAAsC,CAAE,OAAO,CNyF1B,GAAO,CMxF5B,2DAA4C,CAAE,OAAO,CN5I1B,GAAO,CM6IlC,6DAA6C,CAAE,OAAO,CNxI1B,GAAO,CMyInC,0BAA0C,CAAE,OAAO,CNxI1B,GAAO,CMyIhC,4BAA4C,CAAE,OAAO,CNhJ1B,GAAO,CMiJlC,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CNqX1B,GAAO,CMpXvB,gBAAgC,CAAE,OAAO,CNgT1B,GAAO,CM/StB,iBAAiC,CAAE,OAAO,CNuC1B,GAAO,CMtCvB,oBAAoC,CAAE,OAAO,CNxG1B,GAAO,CMyG1B,qBAAqC,CAAE,OAAO,CNzI1B,GAAO,CM0I3B,iCACgC,CAAE,OAAO,CN8V1B,GAAO,CM7VtB,kDAC+B,CAAE,OAAO,CNwH1B,GAAO,CMvHrB,gBAAgC,CAAE,OAAO,CNxD1B,GAAO,CMyDtB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,kCACmC,CAAE,OAAO,CN+N1B,GAAO,CM9NzB,kCACkC,CAAE,OAAO,CNyB1B,GAAO,CMxBxB,oBAAoC,CAAE,OAAO,CN8J1B,GAAO,CM7J1B,mCACmC,CAAE,OAAO,CNiC1B,GAAO,CMhCzB,iBAAiC,CAAE,OAAO,CNkQ1B,GAAO,CMjQvB,qDAE+B,CAAE,OAAO,CN9I1B,GAAO,CM+IrB,kBAAkC,CAAE,OAAO,CNiH1B,GAAO,CMhHxB,kBAAkC,CAAE,OAAO,CN+G1B,GAAO,CM9GxB,wBAAwC,CAAE,OAAO,CN4Q1B,GAAO,CM3Q9B,oBAAoC,CAAE,OAAO,CNgU1B,GAAO,CM/T1B,gBAAgC,CAAE,OAAO,CNkR1B,GAAO,CMjRtB,gBAAgC,CAAE,OAAO,CNmH1B,GAAO,CMlHtB,gBAAgC,CAAE,OAAO,CNmT1B,GAAO,CMlTtB,oBAAoC,CAAE,OAAO,CNgK1B,GAAO,CM/J1B,2BAA2C,CAAE,OAAO,CNgK1B,GAAO,CM/JjC,6BAA6C,CAAE,OAAO,CN8C1B,GAAO,CM7CnC,sBAAsC,CAAE,OAAO,CN4C1B,GAAO,CM3C5B,gBAAgC,CAAE,OAAO,CNgI1B,GAAO,CM/HtB,wEAAqC,CAAE,OAAO,CNxH1B,GAAO,CMyH3B,mBAAmC,CAAE,OAAO,CNlH1B,GAAO,CMmHzB,qBAAqC,CAAE,OAAO,CNzH1B,GAAO,CM0H3B,sBAAsC,CAAE,OAAO,CNzH1B,GAAO,CM0H5B,kBAAkC,CAAE,OAAO,CN3E1B,GAAO,CM4ExB,mCAC+B,CAAE,OAAO,CN4N1B,GAAO,CM3NrB,yCACoC,CAAE,OAAO,CNgO1B,GAAO,CM/N1B,sCACmC,CAAE,OAAO,CN6N1B,GAAO,CM5NzB,mBAAmC,CAAE,OAAO,CN/C1B,GAAO,CMgDzB,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,sCAC+B,CAAE,OAAO,CN0S1B,GAAO,CMzSrB,iCACgC,CAAE,OAAO,CNW1B,GAAO,CMVtB,0CACqC,CAAE,OAAO,CN0P1B,GAAO,CMzP3B,oBAAoC,CAAE,OAAO,CNxF1B,GAAO,CMyF1B,qBAAqC,CAAE,OAAO,CNvF1B,GAAO,CMwF3B,gCAC+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,kBAAkC,CAAE,OAAO,CNoM1B,GAAO,CMnMxB,mBAAmC,CAAE,OAAO,CN8R1B,GAAO,CM7RzB,qCACoC,CAAE,OAAO,CN9G1B,GAAO,CM+G1B,sBAAsC,CAAE,OAAO,CNiE1B,GAAO,CMhE5B,mBAAmC,CAAE,OAAO,CN1D1B,GAAO,CM2DzB,yBAAyC,CAAE,OAAO,CN7G1B,GAAO,CM8G/B,uBAAuC,CAAE,OAAO,CN7G1B,GAAO,CM8G7B,kBAAkC,CAAE,OAAO,CNkS1B,GAAO,CMjSxB,sBAAsC,CAAE,OAAO,CNgO1B,GAAO,CM/N5B,mBAAmC,CAAE,OAAO,CNqO1B,GAAO,CMpOzB,iBAAiC,CAAE,OAAO,CNxL1B,GAAO,CMyLvB,iBAAiC,CAAE,OAAO,CN7G1B,GAAO,CM8GvB,kBAAkC,CAAE,OAAO,CN3F1B,GAAO,CM4FxB,sBAAsC,CAAE,OAAO,CNpC1B,GAAO,CMqC5B,qBAAqC,CAAE,OAAO,CNzK1B,GAAO,CM0K3B,qBAAqC,CAAE,OAAO,CNqB1B,GAAO,CMpB3B,oBAAoC,CAAE,OAAO,CN3O1B,GAAO,CM4O1B,iBAAiC,CAAE,OAAO,CN4E1B,GAAO,CM3EvB,sBAAsC,CAAE,OAAO,CNxD1B,GAAO,CMyD5B,eAA+B,CAAE,OAAO,CNrM1B,GAAO,CMsMrB,mBAAmC,CAAE,OAAO,CNG1B,GAAO,CMFzB,sBAAsC,CAAE,OAAO,CNuH1B,GAAO,CMtH5B,4BAA4C,CAAE,OAAO,CN5O1B,GAAO,CM6OlC,6BAA6C,CAAE,OAAO,CN5O1B,GAAO,CM6OnC,0BAA0C,CAAE,OAAO,CN5O1B,GAAO,CM6OhC,4BAA4C,CAAE,OAAO,CNhP1B,GAAO,CMiPlC,qBAAqC,CAAE,OAAO,CN5O1B,GAAO,CM6O3B,sBAAsC,CAAE,OAAO,CN5O1B,GAAO,CM6O5B,mBAAmC,CAAE,OAAO,CN5O1B,GAAO,CM6OzB,qBAAqC,CAAE,OAAO,CNhP1B,GAAO,CMiP3B,kBAAkC,CAAE,OAAO,CNxG1B,GAAO,CMyGxB,iBAAiC,CAAE,OAAO,CNyB1B,GAAO,CMxBvB,iBAAiC,CAAE,OAAO,CNmN1B,GAAO,CMlNvB,yCACiC,CAAE,OAAO,CNmE1B,GAAO,CMlEvB,mBAAmC,CAAE,OAAO,CNlJ1B,GAAO,CMmJzB,qBAAqC,CAAE,OAAO,CNiH1B,GAAO,CMhH3B,sBAAsC,CAAE,OAAO,CNiH1B,GAAO,CMhH5B,kBAAkC,CAAE,OAAO,CNiL1B,GAAO,CMhLxB,iBAAiC,CAAE,OAAO,CNvJ1B,GAAO,CMwJvB,sCACgC,CAAE,OAAO,CNyH1B,GAAO,CMxHtB,qBAAqC,CAAE,OAAO,CN9B1B,GAAO,CM+B3B,mBAAmC,CAAE,OAAO,CNjD1B,GAAO,CMkDzB,wBAAwC,CAAE,OAAO,CNhD1B,GAAO,CMiD9B,kBAAkC,CAAE,OAAO,CN2J1B,GAAO,CM1JxB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,gBAAgC,CAAE,OAAO,CN+C1B,GAAO,CM9CtB,kBAAkC,CAAE,OAAO,CN9C1B,GAAO,CM+CxB,qBAAqC,CAAE,OAAO,CNI1B,GAAO,CMH3B,iBAAiC,CAAE,OAAO,CN9D1B,GAAO,CM+DvB,yBAAyC,CAAE,OAAO,CNhE1B,GAAO,CMiE/B,mBAAmC,CAAE,OAAO,CNsM1B,GAAO,CMrMzB,eAA+B,CAAE,OAAO,CN1J1B,GAAO,CM2JrB,8CACoC,CAAE,OAAO,CN4G1B,GAAO,CM3G1B,2EAEsC,CAAE,OAAO,CNwK1B,GAAO,CMvK5B,yBAAyC,CAAE,OAAO,CNmB1B,GAAO,CMlB/B,eAA+B,CAAE,OAAO,CNjJ1B,GAAO,CMkJrB,oBAAoC,CAAE,OAAO,CNjK1B,GAAO,CMkK1B,yCACuC,CAAE,OAAO,CN9L1B,GAAO,CM+L7B,mBAAmC,CAAE,OAAO,CNmF1B,GAAO,CMlFzB,eAA+B,CAAE,OAAO,CNvB1B,GAAO,CMwBrB,sBAAsC,CAAE,OAAO,CNvH1B,GAAO,CMwH5B,sBAAsC,CAAE,OAAO,CN6K1B,GAAO,CM5K5B,oBAAoC,CAAE,OAAO,CNyK1B,GAAO,CMxK1B,iBAAiC,CAAE,OAAO,CN9H1B,GAAO,CM+HvB,uBAAuC,CAAE,OAAO,CN0E1B,GAAO,CMzE7B,qBAAqC,CAAE,OAAO,CNwB1B,GAAO,CMvB3B,2BAA2C,CAAE,OAAO,CNwB1B,GAAO,CMvBjC,iBAAiC,CAAE,OAAO,CNqH1B,GAAO,CMpHvB,qBAAqC,CAAE,OAAO,CN9N1B,GAAO,CM+N3B,4BAA4C,CAAE,OAAO,CN1F1B,GAAO,CM2FlC,iBAAiC,CAAE,OAAO,CN2F1B,GAAO,CM1FvB,iBAAiC,CAAE,OAAO,CNc1B,GAAO,CMbvB,8BAA8C,CAAE,OAAO,CNtM1B,GAAO,CMuMpC,+BAA+C,CAAE,OAAO,CNtM1B,GAAO,CMuMrC,4BAA4C,CAAE,OAAO,CNtM1B,GAAO,CMuMlC,8BAA8C,CAAE,OAAO,CN1M1B,GAAO,CM2MpC,gBAAgC,CAAE,OAAO,CN7C1B,GAAO,CM8CtB,eAA+B,CAAE,OAAO,CNtK1B,GAAO,CMuKrB,iBAAiC,CAAE,OAAO,CN9S1B,GAAO,CM+SvB,qBAAqC,CAAE,OAAO,CN+M1B,GAAO,CM9M3B,mBAAmC,CAAE,OAAO,CN/O1B,GAAO,CMgPzB,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ3B,qBAAqC,CAAE,OAAO,CNmF1B,GAAO,CMlF3B,sBAAsC,CAAE,OAAO,CN6C1B,GAAO,CM5C5B,iBAAiC,CAAE,OAAO,CN0K1B,GAAO,CMzKvB,uBAAuC,CAAE,OAAO,CNO1B,GAAO,CMN7B,wIAAyC,CAAE,OAAO,CNO1B,GAAO,CMN/B,mBAAmC,CAAE,OAAO,CN/B1B,GAAO,CMgCzB,qBAAqC,CAAE,OAAO,CNjC1B,GAAO,CMkC3B,uBAAuC,CAAE,OAAO,CN3N1B,GAAO,CM4N7B,wBAAwC,CAAE,OAAO,CNyB1B,GAAO,CMxB9B,+BAA+C,CAAE,OAAO,CNlJ1B,GAAO,CMmJrC,uBAAuC,CAAE,OAAO,CNuF1B,GAAO,CMtF7B,kBAAkC,CAAE,OAAO,CN9L1B,GAAO,CM+LxB,qDAC8C,CAAE,OAAO,CNnP1B,GAAO,CMoPpC,iDAC4C,CAAE,OAAO,CNlP1B,GAAO,CMmPlC,uDAC+C,CAAE,OAAO,CNrP1B,GAAO,CMsPrC,8BAC8B,CAAE,OAAO,CNpK1B,GAAO,CMqKpB,cAA8B,CAAE,OAAO,CNzG1B,GAAO,CM0GpB,gCAC8B,CAAE,OAAO,CNwL1B,GAAO,CMvLpB,+BAC8B,CAAE,OAAO,CNrE1B,GAAO,CMsEpB,2DAG8B,CAAE,OAAO,CNnE1B,GAAO,CMoEpB,iDAE8B,CAAE,OAAO,CNqD1B,GAAO,CMpDpB,6BAC8B,CAAE,OAAO,CNpE1B,GAAO,CMqEpB,iCAC8B,CAAE,OAAO,CN1R1B,GAAO,CM2RpB,eAA+B,CAAE,OAAO,CNlK1B,GAAO,CMmKrB,oBAAoC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ1B,yBAAyC,CAAE,OAAO,CN4E1B,GAAO,CM3E/B,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,0BAA0C,CAAE,OAAO,CN4E1B,GAAO,CM3EhC,2BAA2C,CAAE,OAAO,CN4E1B,GAAO,CM3EjC,2BAA2C,CAAE,OAAO,CN+E1B,GAAO,CM9EjC,4BAA4C,CAAE,OAAO,CN+E1B,GAAO,CM9ElC,oBAAoC,CAAE,OAAO,CN+H1B,GAAO,CM9H1B,sBAAsC,CAAE,OAAO,CN2H1B,GAAO,CM1H5B,yBAAyC,CAAE,OAAO,CN4L1B,GAAO,CM3L/B,kBAAkC,CAAE,OAAO,CNyL1B,GAAO,CMxLxB,eAA+B,CAAE,OAAO,CNmL1B,GAAO,CMlLrB,sBAAsC,CAAE,OAAO,CNmL1B,GAAO,CMlL5B,uBAAuC,CAAE,OAAO,CNuL1B,GAAO,CMtL7B,kBAAkC,CAAE,OAAO,CN/M1B,GAAO,CMgNxB,yBAAyC,CAAE,OAAO,CNgF1B,GAAO,CM/E/B,oBAAoC,CAAE,OAAO,CNjG1B,GAAO,CMkG1B,iBAAiC,CAAE,OAAO,CNxJ1B,GAAO,CMyJvB,cAA8B,CAAE,OAAO,CNhX1B,GAAO,CMiXpB,2CAAoC,CAAE,OAAO,CNzT1B,GAAO,CM0T1B,2BAA2C,CAAE,OAAO,CNzT1B,GAAO,CM0TjC,iBAAiC,CAAE,OAAO,CNqI1B,GAAO,CMpIvB,wBAAwC,CAAE,OAAO,CNqI1B,GAAO,CMpI9B,0BAA0C,CAAE,OAAO,CNrE1B,GAAO,CMsEhC,wBAAwC,CAAE,OAAO,CNnE1B,GAAO,CMoE9B,0BAA0C,CAAE,OAAO,CNtE1B,GAAO,CMuEhC,2BAA2C,CAAE,OAAO,CNtE1B,GAAO,CMuEjC,gBAAgC,CAAE,OAAO,CNxW1B,GAAO,CMyWtB,kBAAkC,CAAE,OAAO,CN8J1B,GAAO,CM7JxB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,gBAAgC,CAAE,OAAO,CNnF1B,GAAO,CMoFtB,mBAAmC,CAAE,OAAO,CNjO1B,GAAO,CMkOzB,gBAAgC,CAAE,OAAO,CNsC1B,GAAO,CMrCtB,qBAAqC,CAAE,OAAO,CNhK1B,GAAO,CMiK3B,iBAAiC,CAAE,OAAO,CNmH1B,GAAO,CMlHvB,iBAAiC,CAAE,OAAO,CNxM1B,GAAO,CMyMvB,eAA+B,CAAE,OAAO,CNzE1B,GAAO,CM0ErB,iBAAiC,CAAE,OAAO,CNrJ1B,GAAO,CMsJvB,gBAAgC,CAAE,OAAO,CN2E1B,GAAO,CM1EtB,iBAAiC,CAAE,OAAO,CN7D1B,GAAO,CM8DvB,kBAAkC,CAAE,OAAO,CNpX1B,GAAO,CMqXxB,cAA8B,CAAE,OAAO,CNpU1B,GAAO,CMqUpB,aAA6B,CAAE,OAAO,CNsI1B,GAAO,CMrInB,gBAAgC,CAAE,OAAO,CN2I1B,GAAO,CM1ItB,iBAAiC,CAAE,OAAO,CNX1B,GAAO,CMYvB,oBAAoC,CAAE,OAAO,CN5D1B,GAAO,CM6D1B,yBAAyC,CAAE,OAAO,CNgD1B,GAAO,CM/C/B,+BAA+C,CAAE,OAAO,CNrX1B,GAAO,CMsXrC,8BAA8C,CAAE,OAAO,CNvX1B,GAAO,CMwXpC,qDAC8C,CAAE,OAAO,CN5T1B,GAAO,CM6TpC,uBAAuC,CAAE,OAAO,CNvP1B,GAAO,CMwP7B,qBAAqC,CAAE,OAAO,CNoI1B,GAAO,CMnI3B,uBAAuC,CAAE,OAAO,CNyH1B,GAAO,CMxH7B,sCAC8B,CAAE,OAAO,CNiG1B,GAAO,CMhGpB,wEAAwC,CAAE,OAAO,CNzC1B,GAAO,CM0C9B,wBAAwC,CAAE,OAAO,CN+B1B,GAAO,CM9B9B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,0BAA0C,CAAE,OAAO,CNnP1B,GAAO,CMoPhC,oBAAoC,CAAE,OAAO,CNgI1B,GAAO,CM/H1B,iBAAiC,CAAE,OAAO,CN9E1B,GAAO,CM+EvB,4DAEqC,CAAE,OAAO,CNmG1B,GAAO,CMlG3B,iDACyC,CAAE,OAAO,CN3K1B,GAAO,CM4K/B,gBAAgC,CAAE,OAAO,CN6H1B,GAAO,CM5HtB,iBAAiC,CAAE,OAAO,CNjL1B,GAAO,CMkLvB,iBAAiC,CAAE,OAAO,CNxC1B,GAAO,CMyCvB,wBAAwC,CAAE,OAAO,CNxC1B,GAAO,CMyC9B,6BAA6C,CAAE,OAAO,CNuC1B,GAAO,CMtCnC,sBAAsC,CAAE,OAAO,CNqC1B,GAAO,CMpC5B,oBAAoC,CAAE,OAAO,CNlR1B,GAAO,CMmR1B,eAA+B,CAAE,OAAO,CNhR1B,GAAO,CMiRrB,qBAAqC,CAAE,OAAO,CNxE1B,GAAO,CMyE3B,yBAAyC,CAAE,OAAO,CNxE1B,GAAO,CMyE/B,iBAAiC,CAAE,OAAO,CN7Q1B,GAAO,CM8QvB,iBAAiC,CAAE,OAAO,CN3J1B,GAAO,CM4JvB,mBAAmC,CAAE,OAAO,CNtJ1B,GAAO,CMuJzB,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,mBAAmC,CAAE,OAAO,CN3W1B,GAAO,CM4WzB,gBAAgC,CAAE,OAAO,CNjU1B,GAAO,CMkUtB,cAA8B,CAAE,OAAO,CN1F1B,GAAO,CM2FpB,gBAAgC,CAAE,OAAO,CNM1B,GAAO,CMLtB,eAA+B,CAAE,OAAO,CNrS1B,GAAO,CMsSrB,gBAAgC,CAAE,OAAO,CNrS1B,GAAO,CMsStB,kBAAkC,CAAE,OAAO,CNtY1B,GAAO,CMuYxB,yBAAyC,CAAE,OAAO,CNtY1B,GAAO,CMuY/B,gBAAgC,CAAE,OAAO,CNa1B,GAAO,CMZtB,uBAAuC,CAAE,OAAO,CNa1B,GAAO,CMZ7B,kBAAkC,CAAE,OAAO,CN/D1B,GAAO,CMgExB,oCAC8B,CAAE,OAAO,CN5W1B,GAAO,CM6WpB,8BAC+B,CAAE,OAAO,CN2B1B,GAAO,CM1BrB,eAA+B,CAAE,OAAO,CNoD1B,GAAO,CMnDrB,kBAAkC,CAAE,OAAO,CNN1B,GAAO,CMOxB,qBAAqC,CAAE,OAAO,CNzS1B,GAAO,CM0S3B,qBAAqC,CAAE,OAAO,CNZ1B,GAAO,CMa3B,mBAAmC,CAAE,OAAO,CN/S1B,GAAO,CMgTzB,qBAAqC,CAAE,OAAO,CNhQ1B,GAAO,CMiQ3B,sBAAsC,CAAE,OAAO,CNzP1B,GAAO,CM0P5B,uBAAuC,CAAE,OAAO,CNtQ1B,GAAO,CMuQ7B,4BAA4C,CAAE,OAAO,CNhQ1B,GAAO,CMiQlC,yEAEuC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q7B,+CACyC,CAAE,OAAO,CN/Q1B,GAAO,CMgR/B,+CACuC,CAAE,OAAO,CNhR1B,GAAO,CMiR7B,+CACuC,CAAE,OAAO,CNrQ1B,GAAO,CMsQ7B,sBAAsC,CAAE,OAAO,CNlR1B,GAAO,CMmR5B,eAA+B,CAAE,OAAO,CN4D1B,GAAO,CM3DrB,kBAAkC,CAAE,OAAO,CNrV1B,GAAO,CMsVxB,mBAAmC,CAAE,OAAO,CNhM1B,GAAO,CMiMzB,uGAIoC,CAAE,OAAO,CNtL1B,GAAO,CMuL1B,yBAAyC,CAAE,OAAO,CNvW1B,GAAO,CMwW/B,8BACgC,CAAE,OAAO,CNlG1B,GAAO,CMmGtB,+BACiC,CAAE,OAAO,CN1T1B,GAAO,CM2TvB,qBAAqC,CAAE,OAAO,CNpP1B,GAAO,CMqP3B,cAA8B,CAAE,OAAO,CNtP1B,GAAO,CMuPpB,sBAAsC,CAAE,OAAO,CNxO1B,GAAO,CMyO5B,wBAAwC,CAAE,OAAO,CNR1B,GAAO,CMS9B,aAA6B,CAAE,OAAO,CNjH1B,GAAO,CMkHnB,mCACiC,CAAE,OAAO,CNiD1B,GAAO,CMhDvB,sCACsC,CAAE,OAAO,CNrJ1B,GAAO,CMsJ5B,0CACwC,CAAE,OAAO,CNtJ1B,GAAO,CMuJ9B,kBAAkC,CAAE,OAAO,CNvO1B,GAAO,CMwOxB,sBAAsC,CAAE,OAAO,CNvX1B,GAAO,CMwX5B,iBAAiC,CAAE,OAAO,CN7O1B,GAAO,CM8OvB,oBAAoC,CAAE,OAAO,CNxJ1B,GAAO,CMyJ1B,kBAAkC,CAAE,OAAO,CNvE1B,GAAO,CMwExB,oBAAoC,CAAE,OAAO,CNtF1B,GAAO,CMuF1B,2BAA2C,CAAE,OAAO,CNtF1B,GAAO,CMuFjC,eAA+B,CAAE,OAAO,CNnb1B,GAAO,CMobrB,4CACmC,CAAE,OAAO,CNjR1B,GAAO,CMkRzB,cAA8B,CAAE,OAAO,CNI1B,GAAO,CMHpB,qBAAqC,CAAE,OAAO,CN9b1B,GAAO,CM+b3B,eAA+B,CAAE,OAAO,CN5I1B,GAAO,CM6IrB,qBAAqC,CAAE,OAAO,CN/E1B,GAAO,CMgF3B,iBAAiC,CAAE,OAAO,CNI1B,GAAO,CMHvB,eAA+B,CAAE,OAAO,CNuC1B,GAAO,CMtCrB,sBAAsC,CAAE,OAAO,CN7K1B,GAAO,CM8K5B,eAA+B,CAAE,OAAO,CN6B1B,GAAO,CM5BrB,qBAAqC,CAAE,OAAO,CNjb1B,GAAO,CMkb3B,iBAAiC,CAAE,OAAO,CNpK1B,GAAO,CMqKvB,wBAAwC,CAAE,OAAO,CNzQ1B,GAAO,CM0Q9B,kBAAkC,CAAE,OAAO,CNha1B,GAAO,CMiaxB,wBAAwC,CAAE,OAAO,CNpa1B,GAAO,CMqa9B,sBAAsC,CAAE,OAAO,CNta1B,GAAO,CMua5B,kBAAkC,CAAE,OAAO,CNxa1B,GAAO,CMyaxB,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,oBAAoC,CAAE,OAAO,CNta1B,GAAO,CMua1B,qBAAqC,CAAE,OAAO,CNjd1B,GAAO,CMkd3B,uBAAuC,CAAE,OAAO,CNjd1B,GAAO,CMkd7B,gBAAgC,CAAE,OAAO,CNtB1B,GAAO,CMuBtB,oBAAoC,CAAE,OAAO,CN9X1B,GAAO,CM+X1B,aAA6B,CAAE,OAAO,CNne1B,GAAO,CMoenB,qBAAqC,CAAE,OAAO,CNtV1B,GAAO,CMuV3B,sBAAsC,CAAE,OAAO,CN1L1B,GAAO,CM2L5B,wBAAwC,CAAE,OAAO,CNpd1B,GAAO,CMqd9B,qBAAqC,CAAE,OAAO,CNzf1B,GAAO,CM0f3B,oBAAoC,CAAE,OAAO,CN7K1B,GAAO,CM8K1B,qBAAqC,CAAE,OAAO,CNzO1B,GAAO,CM0O3B,iBAAiC,CAAE,OAAO,CNtP1B,GAAO,CMuPvB,wBAAwC,CAAE,OAAO,CNtP1B,GAAO,CMuP9B,qBAAqC,CAAE,OAAO,CNrC1B,GAAO,CMsC3B,oBAAoC,CAAE,OAAO,CNrC1B,GAAO,CMsC1B,kBAAkC,CAAE,OAAO,CN9d1B,GAAO,CM+dxB,cAA8B,CAAE,OAAO,CN5c1B,GAAO,CM6cpB,kBAAkC,CAAE,OAAO,CNtQ1B,GAAO,CMuQxB,oBAAoC,CAAE,OAAO,CN9gB1B,GAAO,CM+gB1B,aAA6B,CAAE,OAAO,CN/b1B,GAAO,CMgcnB,kDAE8B,CAAE,OAAO,CNpR1B,GAAO,CMqRpB,mBAAmC,CAAE,OAAO,CN/N1B,GAAO,COtUzB,swBAAK,CACH,WAAW,CAAE,OAAO,CACpB,y5BAAQ,CACN,WAAW,CC+BuB,aAAa,CD9B/C,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,CAAC,CACd,eAAe,CAAE,OAAO,CAM5B,86BAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,eAAe,CAAE,OAAO,CAGxB,muEAAgB,CACd,OAAO,CAAE,MAAM,CACf,2wEAAuB,CACrB,WAAW,CAAE,KAAI,CACnB,utEAAsB,CACpB,OAAO,CAAE,YAAY,CAE3B,2iBAA2B,CACzB,OAAO,CAAE,GAAE,CfpBL,kBAAoB,CAAE,qBAAM,CAK5B,eAAiB,CAAE,qBAAM,CAezB,UAAY,CAAE,qBAAM,CeE5B,+nBAAiC,CAC/B,OAAO,CAAE,CAAC,CAGV,mtCAAuB,CACrB,SAAS,CAAE,IAAI,CACf,cAAc,CAAE,IAAI,CEpBxB,0PAAS,CACP,OAAO,CAAE,IAAqB,CAC9B,WAAW,CDayB,IAAI,CCZxC,aAAa,CDYuB,IAAI,CCXxC,UAAU,CAAE,OAAmB,CAEjC,8CAAe,CACb,KAAK,CCY+B,IAAM,CDX1C,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CCS+B,IAAM,CDR1C,UAAU,CAAE,OAAkB,CAC9B,MAAM,CAAE,KAAsB,CAC9B,OAAO,CAAE,QAA2C,CACpD,aAAa,CAAE,IAAqB,CAEtC,0ZAAyB,CACvB,UAAU,CAAE,OAAkB,CAC9B,mxCAAe,CACb,UAAU,CAAE,OAAiB,CACjC,kYAA0B,CACxB,UAAU,CAAE,OAAmB,CAC/B,ouCAAe,CACb,UAAU,CAAE,OAAoB,CAEpC,sYAAuB,CACrB,UAAU,CAAE,OAAmB,CAC/B,yuCAAe,CACb,UAAU,CAAE,OAAkB,CAElC,mZAA0B,CACxB,UAAU,CAAE,OAAuB,CACnC,swCAAe,CACb,UAAU,CAAE,OAAqB,CAErC,scAA0B,CACxB,UAAU,CCL0B,OAAmB,CDMvD,42CAAe,CACb,KAAK,CCvB6B,OAAW,CDwB7C,UAAU,CCNwB,OAAmB,CDOvD,8dAAC,CACC,KAAK,CChB6B,OAAK,CDkB3C,sZAAsB,CACpB,aAAa,CAAE,CAAC,CAsBlB,kBAAkB,CAChB,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,GAAG,CACX,IAAI,CAAE,CAAC,CACP,OAAO,CDG6B,GAAG,CCFvC,qBAAE,CACA,OAAO,CAAE,KAAK,CACd,KAAK,CDT6B,KAAK,CCUvC,UAAU,CAAE,WAAW,CACvB,KAAK,CCxD6B,IAAM,CDyDxC,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,MAAmB,CAC5B,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CACT,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,MAAM,CjB3FZ,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiByExB,0CAAsB,CACpB,UAAU,CC5FsB,OAAM,CD6FxC,uCAAmB,CACjB,UAAU,CC/DsB,OAAK,CDgEvC,0CAAsB,CACpB,UAAU,CDnFsB,OAAO,CCoFzC,yCAAqB,CACnB,UAAU,CDtEsB,OAAI,CCuEtC,wBAAI,CACF,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,IAAI,CEhFd,oCAAsB,CFmFxB,kBAAkB,CAChB,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,CAAC,CACN,KAAK,CAAE,IAAI,CACX,qBAAE,CACA,KAAK,CAAE,IAAI,EG3FjB,MAAM,CACJ,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CACvB,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,MAAM,CACnB,kBAAkB,CAAE,MAAM,CAC1B,SAAS,CAAE,OAAO,CACpB,gDAAiD,CAC/C,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,gBAAgB,CACd,MAAM,CAAE,OAAO,CAEjB,IAAI,CAEF,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAClB,WAAW,CAAE,MAAM,CACnB,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,MAAM,CAAE,OAAO,CACf,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,iBAA6F,CACtG,KAAK,CFlB+B,IAAM,CEmB1C,MAAM,CAAE,yBAAyB,CACjC,gBAAgB,CF7CoB,OAAM,CE8C1C,eAAe,CAAE,IAAI,CACrB,WAAW,CAAE,MAAM,CACnB,WAAW,CFJyB,uDAAM,CEK1C,UAAU,CAAE,mFAA8C,CAC1D,YAAY,CAAE,KAAK,CACnB,cAAc,CAAE,MAAM,CACtB,QAAQ,CAAE,MAAM,CAChB,IAAI,CAAE,CAAC,CACP,iBAAiB,CAAE,IAAI,CpBxDjB,mBAAoB,CoByDb,IAAI,CpBpDX,gBAAiB,CoBoDV,IAAI,CpB/CX,eAAgB,CoB+CT,IAAI,CpBrCX,WAAY,CoBqCL,IAAI,CpBzDX,kBAAoB,CAAE,eAAM,CAK5B,eAAiB,CAAE,eAAM,CAezB,UAAY,CAAE,eAAM,CoByC5B,UAAU,CACR,UAAU,CAAE,OAAwB,CACpC,KAAK,CFpC+B,IAAM,CEuC1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,KAAK,CFzC6B,IAAM,CE0C1C,UAAO,CACL,UAAU,CAAE,OAAqC,CACjD,OAAO,CAAE,CAAC,CACZ,WAAQ,CACN,UAAU,CAAE,6EAAyC,CACrD,OAAO,CAAE,iBAA6F,CACxG,YAAS,CACP,KAAK,CFjD6B,IAAM,CEkD1C,aAAU,CACR,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAEpB,aAAa,CACX,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAChB,4DAA0B,CACxB,gBAAgB,CAAE,IAAI,CACtB,MAAM,CAAE,2DAA2D,CACnE,MAAM,CAAE,iBAAmB,CAC3B,OAAO,CAAE,GAAI,CACb,MAAM,CAAE,WAAW,CACnB,UAAU,CAAE,IAAI,CAGpB,sBAAsB,CACpB,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CAEX,UAAU,CACR,SAAS,CAAE,GAAG,CAEhB,SAAS,CACP,gBAAgB,CAAE,kBAAgB,CAClC,eAAO,CACL,gBAAgB,CAAE,kBAA6B,CAEnD,YAAY,CACV,gBAAgB,CAAE,kBAA2C,CAC7D,KAAK,CAAE,kBAAsB,CAC7B,kBAAO,CACL,gBAAgB,CAAE,kBAAuD,CACzE,KAAK,CF/F6B,OAAW,CEgG/C,oBAAS,CACP,KAAK,CAAE,kBAAsB,CAEjC,YAAY,CACV,gBAAgB,CAAE,kBAAiB,CACnC,kBAAO,CACL,gBAAgB,CAAE,eAA6B,CAEnD,WAAW,CACT,gBAAgB,CAAE,kBAAe,CACjC,iBAAO,CACL,gBAAgB,CAAE,kBAA4B,CAElD,YAAY,CACV,gBAAgB,CAAE,kBAAkB,CACpC,kBAAO,CACL,gBAAgB,CAAE,kBAA+B,CACrD,WAAW,CACT,gBAAgB,CJvIoB,IAAI,CIwIxC,iBAAO,CACL,gBAAgB,CAAE,kBAAoC,CAE1D,SAAS,CACP,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CF9G+B,OAAK,CE+GzC,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,sBAAsB,CACpC,eAAO,CACL,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,gBAAQ,CACN,gBAAgB,CAAE,sBAAsB,CACxC,KAAK,CAAE,kBAAoC,CAC3C,UAAU,CAAE,IAAI,CAClB,iBAAS,CACP,KAAK,CFzH6B,OAAO,CE2H7C,mCAAoC,CAClC,cAAc,CAAE,MAAM,CAExB,aAAa,CACX,aAAa,CJ1IuB,IAAI,CduExC,KAAK,CAAE,CAAC,CACR,wCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,mBAAO,CACL,KAAK,CAAE,IAAI,CmB3Ff,YAAY,CACV,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,YAAY,CAIvB,qCAAqC,CACnC,OAAO,CAAE,KAAK,CAChB,iBAAiB,CACf,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,CAAC,CACP,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,IAAI,CACX,GAAG,CAAE,IAAI,CACT,SAAS,CAAE,IAAI,CACf,UAAU,CHQ0B,OAAyB,CGP7D,OAAO,CLmD6B,GAAG,CKlDvC,MAAM,CAAE,iBAAgC,CACxC,UAAU,CAAE,2BAA0B,CACtC,OAAO,CAAE,IAAqB,CAC9B,sBAAQ,CACN,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,KAAK,CHT6B,OAAW,CGU7C,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,MAAuB,CAChC,MAAM,CAAE,OAAO,CACf,4BAAO,CACL,UAAU,CHLsB,OAAK,CGMrC,KAAK,CHZ2B,IAAM,CGa1C,4BAAY,CACV,UAAU,CAAE,iBAAgC,CAC5C,MAAM,CAAE,KAAuB,CACjC,2BAAW,CACT,cAAc,CAAE,IAAqB,CACrC,gDAAoB,CAClB,KAAK,CAAE,IAAI,CACf,mCAAmB,CACjB,UAAU,CAAE,OAA4B,CACxC,cAAc,CAAE,SAAS,CACzB,WAAW,CAAE,GAAG,CAChB,SAAS,CAAE,GAAG,CACd,yCAAO,CACL,UAAU,CAAE,OAA4B,CAC1C,wCAAI,CACF,KAAK,CH5B2B,IAAM,CG8B5C,6CAA6C,CAC3C,MAAM,CAAE,IAAI,CACZ,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,IAAI,CACV,KAAK,CAAE,CAAC,CAGR,iDAAiB,CACf,UAAU,CHjCwB,OAAyB,CGkC3D,UAAU,CAAE,GAAG,CACjB,mDAAmB,CACjB,OAAO,CAAE,QAA2C,CACpD,yDAAO,CACL,UAAU,CHrCsB,OAAK,CGsCrC,KAAK,CH5C2B,IAAM,CG8C5C,+CAA+C,CAC7C,KAAK,CAAE,CAAC,CACR,IAAI,CAAE,IAAI,CACV,UAAU,CAAE,KAAK,CAGjB,yBAAQ,CACN,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,iBAA0B,CACzC,WAAW,CAAE,qBAAqB,CAClC,YAAY,CAAE,qBAAqB,CACnC,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,KAAK,CACd,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,GAAG,CACT,WAAW,CAAE,IAAI,CACnB,gDAA+B,CAC7B,IAAI,CAAE,IAAI,CCtEZ,uBAAM,CACJ,OAAO,CAAE,KAAK,CAEhB,gIAA+C,CAC7C,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAItB,wCAAO,CACL,OAAO,CAAE,YAAY,CACrB,cAAc,CAAE,MAAM,CACtB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,YAA+C,CACvD,KAAK,CAAE,IAAI,CACf,4BAAW,CACT,KAAK,CAAE,IAAI,CACX,kCAAK,CACH,OAAO,CAAE,KAAK,CAChB,mCAAM,CACJ,UAAU,CAAE,GAAqB,CAEvC,QAAQ,CACN,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACZ,MAAM,CACJ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,WAAW,CAAE,MAAM,CACnB,aAAa,CN/BuB,IAAI,CMgCxC,SAAS,CAAE,IAAI,CACf,YAAY,CAAE,IAAI,CACpB,KAAK,CACH,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,cAAa,CACrB,KAAK,CNR+B,IAAU,CMS9C,SAAS,CAAE,GAAG,CAEhB,qBAAuB,CACrB,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,CAAC,CACT,cAAc,CAAE,QAAQ,CACxB,eAAe,CAAE,MAAM,CAGzB,iBAAiB,CACf,aAAa,CNhDuB,IAAI,CduExC,KAAK,CAAE,CAAC,CqBrGR,SAAS,CCCC,IAAQ,CDChB,WAAI,CAAE,IAAI,CACV,YAAK,CAAE,IAAI,CrBkGb,KAAK,CAAE,CAAC,CACR,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CALb,gDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,uBAAO,CACL,KAAK,CAAE,IAAI,CoBzBf,uDAAyD,CACvD,OAAO,CAAE,IAAI,CACb,KAAK,CN/C+B,OAAI,CMoDxC,mGAA+C,CAC7C,cAAc,CAAE,IAAqB,CACrC,wHAAM,CACJ,KAAK,CAAE,IAAI,CAEX,0tEAAqP,CACnP,KAAK,CAAE,IAAI,CACnB,+BAA+B,CGlF3B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,IAAuC,CCnB5C,YAAoB,CAAE,CAAC,CDqBzB,0CAAa,CACX,YAAoB,CAAE,CAAC,CHgE/B,iCAAiC,CGtF7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJqEzD,iCAAiC,CG1F7B,KAAK,CAAE,IAAsB,CAG3B,OAAO,CAAE,KAAK,CAed,YAAoB,CAAE,QAA+B,CACrD,KAAK,CAAE,SAAuC,CAE9C,4CAAa,CACX,YAAoB,CAAE,CAAC,CCA7B,iDAAwB,CACtB,YAAoB,CAAE,CAAC,CAEvB,mDAA0B,CACxB,KAAK,CALY,IAAkC,CJ0EzD,uDAAuD,CACrD,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAEhB,oBAAoB,CAClB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,SAA2B,CACnC,SAAS,CAAE,GAAG,CAOZ,osBAAqP,CACnP,KAAK,CAAE,IAAI,CAIjB,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,YAAY,CAAE,KAAK,CACnB,KAAK,CAAE,IAAI,CACX,cAAc,CAAE,MAAM,CACtB,SAAS,CAAE,GAAG,CAEhB,gBAAgB,CACd,OAAO,CAAE,KAAK,CACd,KAAK,CJxH+B,IAAW,CIyH/C,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,QAAO,CACnB,UAAU,CAAE,MAAM,CAClB,kBAAC,CACC,SAAS,CAAE,OAAO,CAClB,UAAU,CAAE,MAAM,CAClB,aAAa,CAAE,GAAqB,CACtC,6BAAY,CACV,aAAa,CAAE,CAAC,CA4DpB,KAAK,CACH,WAAW,CAAE,MAAM,CAGnB,6DAAmD,CACjD,kBAAkB,CAAE,MAAM,CAC1B,MAAM,CAAE,OAAO,CACf,WAAW,CJhKuB,uDAAM,CIiKxC,SAAS,CAAE,OAAO,CACpB,gSAAqP,CACnP,kBAAkB,CAAE,IAAI,CACxB,OAAO,CAAE,GAAqB,CAC9B,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,WAAW,CJxKuB,uDAAM,CIyKxC,UAAU,CAAE,oBAAmC,CAC/C,aAAa,CAAE,CAAC,CtBxNZ,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsBuM1B,4BAAwB,CACtB,OAAO,CAAE,iBAAkB,CAC7B,eAAW,CACT,MAAM,CAAE,OAAO,CACjB,0CAAmC,CtB/N7B,kBAAoB,CsBgOZ,UAAU,CtB3NlB,eAAiB,CsB2NT,UAAU,CtB5MlB,UAAY,CsB4MJ,UAAU,CACtB,OAAO,CAAE,CAAC,CACV,YAAY,CAAE,QAAO,CACrB,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,IAAI,CACd,oBAAgB,CtBrOV,kBAAoB,CsBsOZ,UAAU,CtBjOlB,eAAiB,CsBiOT,UAAU,CtBlNlB,UAAY,CsBkNJ,UAAU,CACtB,kGAA6D,CAC3D,kBAAkB,CAAE,IAAI,CAC5B,oXAAyU,CACvU,OAAO,CAAE,CAAC,CACV,OAAO,CAAE,cAAc,CACvB,YAAY,CNxLsB,IAAU,CMyL9C,oBAAgB,CACd,YAAY,CAAE,eAA8B,CAC9C,+EAAqE,CACnE,OAAO,CAAE,gBAAsB,CAC/B,OAAO,CAAE,gBAAgB,CAC3B,4aAAiY,CAC/X,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAEzD,+DAAiE,CAC/D,KAAK,CNzN+B,OAAI,CM0NxC,MAAM,CAAE,iBAAc,CACxB,iFAAmF,CACjF,YAAY,CN5NwB,OAAI,CM8NxC,yHAA+G,CAC7G,aAAa,CN/NqB,OAAI,CMiO1C,oBAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,SAAS,CAAE,IAAI,CAKjB,QAAQ,CACN,QAAQ,CAAE,IAAI,CACd,cAAc,CAAE,GAAG,CACnB,KAAK,CAAE,IAAI,CACX,WAAW,CJ5NyB,uDAAM,CI6N5C,eAAgB,CACd,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,cAA6B,CACrC,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,oBAAmC,CtBhRzC,kBAAoB,CAAE,kBAAM,CAK5B,eAAiB,CAAE,kBAAM,CAezB,UAAY,CAAE,kBAAM,CsB+P5B,MAAM,CACJ,MAAM,CAAE,cAA6B,CACrC,gBAAgB,CJ1PoB,IAAM,CI2P1C,gBAAW,CACT,MAAM,CAAE,IAAI,CAChB,2BAA4B,CAC1B,OAAO,CAAE,CAAC,CACZ,uFAA2F,CACzF,MAAM,CAAE,WAAW,CACnB,gBAAgB,CAAE,OAAmC,CAKrD,8DAAuD,CACrD,MAAM,CAAE,WAAW,CACvB,sBAAuB,CACrB,MAAM,CAAE,KAAuB,CAE/B,KAAK,CJ/Q+B,OAAW,CIgR/C,OAAO,CAAE,KAAK,CACd,kCAAK,CACH,cAAc,CAAE,QAAQ,CAI5B,uBAAuB,CACrB,OAAO,CAAE,YAAY,CACrB,QAAQ,CAAE,MAAM,CAChB,KAAK,CAAE,CAAC,CACR,cAAc,CAAE,MAAM,CAuBxB,iCAAkC,CAChC,WAAW,CAAE,MAAM,CACnB,OAAO,CAAE,GAAqB,CAC9B,qEAAiB,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CACd,gBAAgB,CJzSkB,OAAmB,CI0SrD,MAAM,CAAE,cAA6B,CACrC,KAAK,CJxU6B,IAAW,CI0UjD,kCAAkC,CAChC,WAAW,CAAE,CAAC,CAChB,kCAAkC,CAChC,YAAY,CAAE,CAAC,CAcjB,UAAU,CACR,KAAK,CAAE,IAAuB,CAC9B,MAAM,CAAE,IAAqB,CAC7B,MAAM,CAAE,MAAwB,CAChC,QAAQ,CAAE,QAAQ,CAClB,aAAa,CAAE,GAAG,CAClB,UAAU,CNrW0B,IAAI,CMsWxC,MAAM,CAAE,OAAO,CtB5WT,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsB0V1B,iBAAQ,CACN,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,EAAE,CACX,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,GAAG,CAClB,UAAU,CJ3WwB,IAAW,CI4W7C,IAAI,CAAE,IAAI,CACV,GAAG,CAAE,IAAI,CtBvXL,kBAAoB,CAAE,oBAAM,CAK5B,eAAiB,CAAE,oBAAM,CAezB,UAAY,CAAE,oBAAM,CsBqW1B,gBAAO,CACL,OAAO,CAAE,OAAO,CAChB,QAAQ,CAAE,QAAQ,CAClB,IAAI,CAAE,IAAqB,CAC3B,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,IAAI,CACf,KAAK,CNzX6B,IAAI,CM0X1C,iBAAiB,CACf,UAAU,CAAE,OAAmB,CAC/B,wBAAQ,CACN,IAAI,CN5W8B,IAAI,CM6WtC,UAAU,CJlYwB,OAAM,CImY1C,uBAAO,CACL,OAAO,CAAE,MAAM,CAEnB,8CAA+C,CAC7C,MAAM,CAAE,WAAW,CAiDnB,wGAAyB,CACvB,KAAK,CN7Z6B,OAAI,CM+ZtC,81BAAqP,CACnP,MAAM,CAAE,iBAAc,CAC1B,iDAAQ,CACN,MAAM,CAAE,iBAAc,CAE1B,mBAAmB,CACjB,WAAW,CAAE,MAAM,CACnB,qCAAiB,CACf,OAAO,CAAE,aAAgB,CACzB,OAAO,CAAE,YAAY,CACrB,SAAS,CAAE,GAAG,CAClB,gEAAgE,CAC9D,KAAK,CJvc+B,OAAM,CI0c5C,+DAA+D,CAC7D,KAAK,CN/a+B,OAAI,CMkb1C,gEAAgE,CAC9D,KAAK,CNlc+B,OAAO,CMqc7C,6DAA6D,CAC3D,KAAK,CJpb+B,OAAK,CI0b3C,UAAU,CtB3dF,iBAAoB,CAAE,aAAM,CAK5B,cAAiB,CAAE,aAAM,CAKzB,aAAgB,CAAE,aAAM,CAKxB,YAAe,CAAE,aAAM,CAKvB,SAAY,CAAE,aAAM,CsByc5B,WAAW,CtB7dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB2c5B,WAAW,CtB/dH,iBAAoB,CAAE,cAAM,CAK5B,cAAiB,CAAE,cAAM,CAKzB,aAAgB,CAAE,cAAM,CAKxB,YAAe,CAAE,cAAM,CAKvB,SAAY,CAAE,cAAM,CsB6c5B,OAAO,CtBjeC,iBAAoB,CAAE,UAAM,CAK5B,cAAiB,CAAE,UAAM,CAKzB,aAAgB,CAAE,UAAM,CAKxB,YAAe,CAAE,UAAM,CAKvB,SAAY,CAAE,UAAM,CsB+c1B,iBAAW,CtBneL,iBAAoB,CsBoeL,wBAAwB,CtB/dvC,cAAiB,CsB+dF,wBAAwB,CtB1dvC,aAAgB,CsB0dD,wBAAwB,CtBrdvC,YAAe,CsBqdA,wBAAwB,CtBhdvC,SAAY,CsBgdG,wBAAwB,CAC7C,kBAAY,CtBreN,iBAAoB,CsBseL,yBAAyB,CtBjexC,cAAiB,CsBieF,yBAAyB,CtB5dxC,aAAgB,CsB4dD,yBAAyB,CtBvdxC,YAAe,CsBudA,yBAAyB,CtBldxC,SAAY,CsBkdG,yBAAyB,CAC9C,kBAAY,CtBveN,iBAAoB,CsBweL,yBAAyB,CtBnexC,cAAiB,CsBmeF,yBAAyB,CtB9dxC,aAAgB,CsB8dD,yBAAyB,CtBzdxC,YAAe,CsBydA,yBAAyB,CtBpdxC,SAAY,CsBodG,yBAAyB,CAEhD,yCAAyC,CAErC,8BAAqB,CACnB,MAAM,CAAE,SAAS,CAEjB,8ZAAqP,CACnP,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAClB,cAAK,CACH,aAAa,CAAE,KAAK,CACpB,OAAO,CAAE,KAAK,CAEhB,kYAAqO,CACnO,aAAa,CAAE,CAAC,CAElB,wCAAuB,CACrB,aAAa,CAAE,KAAK,CACpB,UAAU,CAAE,IAAI,CAChB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACb,4BAAW,CACT,MAAM,CAAE,WAAW,CACvB,iEAAmE,CACjE,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAuB,EH5ehC,oCAAsB,CQhC1B,YAAY,CAER,OAAO,CAAE,IAAI,ER8Bb,oCAAsB,CQ5B1B,YAAY,CAER,OAAO,CAAE,IAAI,EAEjB,WAAW,CACT,KAAK,CAAE,IAAI,CAEb,YAAY,CACV,KAAK,CAAE,KAAK,CAEd,WAAW,CACT,KAAK,CAAE,IAAI,CC4Cb,mEAAS,CACP,eAAe,CAAE,QAAQ,CACzB,cAAc,CAAE,CAAC,CACjB,WAAW,CAAE,IAAI,CACjB,aAAa,CZ/BuB,IAAI,CYgCxC,2FAAO,CACL,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,6BAAkB,CACxB,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,CACpB,yJAAM,CACJ,SAAS,CZjByB,GAAG,CYkBrC,MAAM,CAAE,CAAC,CACT,QAAQ,CAAE,OAAO,CACjB,OAAO,CZnB2B,QAAmC,CYoBvE,iOAA8B,CAC5B,iBAAiB,CAAE,CAAC,CACtB,qFAAK,CACH,KAAK,CAAE,IAAI,CACX,UAAU,CAAE,IAAI,CAChB,cAAc,CAAE,MAAM,CACtB,WAAW,CAAE,MAAM,CACnB,8FAAE,CACA,WAAW,CZnDqB,IAAI,CYoDpC,aAAa,CAAE,iBAA6B,CAChD,4EAAE,CACA,gBAAgB,CAAE,WAAW,CAC7B,cAAc,CAAE,MAAM,CAE1B,kFAAc,CACZ,WAAW,CAAE,IAAuB,CACpC,mHAAY,CACV,aAAa,CAAE,CAAC,CACpB,4HAA4B,CAC1B,KAAK,CAAE,EAAE,CACT,aAAa,CAAE,CAAC,CAChB,uXAA0C,CACxC,MAAM,CAAE,CAAC,CAEb,mBAAmB,CACjB,KAAK,CVjE+B,IAAY,CUkEhD,SAAS,CAAE,GAAG,CAChB,kBAAkB,CAChB,KAAK,CVpE+B,IAAY,CUqEhD,SAAS,CAAE,GAAG,CAIhB,2HAAyD,CACvD,gBAAgB,CV5DoB,OAAmB,CU8DzD,gBAAgB,CACd,gBAAgB,CV/DoB,OAAmB,CUoEzD,kDAAsB,CACpB,MAAM,CAAE,iBAA6B,CACrC,wDAAE,CACA,aAAa,CAAE,iBAA6B,CAC5C,WAAW,CAAE,iBAA6B,CAC5C,gGAAwB,CACtB,mBAAmB,CAAE,CAAC,CAE1B,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CAGrC,0BAAE,CACA,aAAa,CAAE,iBAA6B,CAC9C,8CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAGxB,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CACxB,+CAAM,CACJ,YAAY,CAAE,SAAS,CACvB,aAAa,CAAE,iBAA6B,CAC9C,2CAAwB,CACtB,mBAAmB,CAAE,CAAC,CAG1B,oBAAoB,CAClB,aAAa,CZhHuB,IAAI,CYiHxC,SAAS,CAAE,IAAI,CACf,QAAQ,CAAE,IAAI,CACd,0BAAK,CACH,aAAa,CAAE,YAAY,CAC3B,2DAAM,CACJ,WAAW,CAAE,MAAM,CCzIzB,CAAC,CACC,KAAK,CX4B+B,OAAK,CW3BzC,eAAe,CAAE,IAAI,CACrB,MAAM,CAAE,OAAO,CACf,OAAO,CACL,KAAK,CbgD6B,OAAwB,Ca/C5D,SAAS,CACP,KAAK,CXuB6B,OAAO,CWG7C,IAAI,CACF,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,MAAM,CAEpB,IAAI,CACF,WAAW,CXIyB,uDAAM,CWH1C,WAAW,CAAE,MAAM,CACnB,KAAK,CXrB+B,OAAW,CWsB/C,UAAU,CAAE,IAAI,CAChB,UAAU,CAAE,MAAM,CAClB,UAAU,CbnD0B,OAAO,CaqD7C,aAAa,CACX,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,UAAU,CAAE,MAAM,CAEpB,cAAc,CACZ,UAAU,CAAE,KAAK,CAEnB,cAAc,CACZ,SAAS,CAAE,IAAI,CAEjB,eAAe,CACb,SAAS,CAAE,IAAI,CAEjB,oBAAqB,CACnB,SAAS,CAAE,GAAG,CAEhB,eAAe,CACb,eAAe,CAAE,YAAY,CAE/B,gBAAgB,CACd,KAAK,CAAE,kBAAkB,CAC3B,uBAAuB,CACrB,KAAK,CAAE,kBAAgC,CACzC,aAAa,CACX,KAAK,CAAE,kBAAgB,CACzB,oBAAoB,CAClB,KAAK,CAAE,kBAA8B,CACvC,gBAAgB,CACd,KAAK,CAAE,kBAAiB,CAC1B,uBAAuB,CACrB,KAAK,CAAE,kBAA+B,CACxC,eAAe,CACb,KAAK,CAAE,kBAAe,CACxB,sBAAsB,CACpB,KAAK,CAAE,kBAA6B,CACtC,gBAAgB,CACd,KAAK,CAAE,kBAAsB,CAC/B,uBAAuB,CACrB,KAAK,CAAE,kBAAoC,CAkB7C,gEAAyB,CACvB,UAAU,CAAE,CAAC,CACb,WAAW,CAAE,GAAG,CAChB,WAAW,CX/DyB,0DAAa,CWiEnD,CAAC,CACC,WAAW,Cb1FyB,IAAI,Ca2FxC,MAAM,CAAE,CAAC,CACT,SAAS,Cb/F2B,IAAI,CagGxC,aAAa,Cb7FuB,IAAI,Ca+F1C,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,0CAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,SAAS,CAAE,IAAI,CAEjB,EAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,iBAA6B,CACzC,MAAM,CAAE,MAAmB,CAC3B,OAAO,CAAE,CAAC,CAEZ,sCAAI,CACF,WAAW,CAAE,MAAM,CACnB,SAAS,CAAE,IAAI,CACf,UAAU,CXxH0B,IAAM,CWyH1C,MAAM,CAAE,iBAAiC,CACzC,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,KAAK,CACd,WAAW,CXtGyB,wMAAQ,CWuG5C,KAAK,Cb1H+B,OAAI,Ca2HxC,UAAU,CAAE,IAAI,CAChB,0CAAY,CACV,SAAS,CAAE,GAAG,CAmClB,wFAAmB,CACjB,UAAU,CAAE,IAAI,CAChB,WAAW,CbzKyB,IAAI,Ca0KxC,aAAa,Cb1KuB,IAAI,Ca2KxC,oGAAE,CACA,UAAU,CAAE,IAAI,CAChB,WAAW,Cb7KuB,IAAI,Ca8KtC,wJAAY,CACV,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,aAAa,CAAE,CAAC,CAClB,gHAAE,CACA,UAAU,CAAE,MAAM,CAClB,4HAAE,CACA,UAAU,CAAE,MAAM,CACtB,4HAAK,CACH,UAAU,CAAE,OAAO,CAEzB,iFAAsB,CACpB,UAAU,CAAE,OAAO,CACnB,WAAW,Cb3LyB,IAAI,Ca4LxC,aAAa,Cb5LuB,IAAI,Ca6LxC,6FAAE,CACA,UAAU,CAAE,OAAO,CACnB,WAAW,Cb/LuB,IAAI,CagMtC,iJAAY,CACV,aAAa,CAAE,CAAC,CAClB,yGAAE,CACA,aAAa,CAAE,CAAC,CAChB,qHAAE,CACA,UAAU,CAAE,IAAI,CCrOxB,kBAAkB,CAChB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CAAE,IAAI,CACnB,OAAO,Cd6B6B,IAAI,Cc5BxC,WAAW,CAAE,IAAqB,CAClC,WAAW,CAAE,GAAG,CAChB,UAAU,CZ8B0B,IAAM,CY7B1C,QAAQ,CAAE,QAAQ,CAClB,wBAAO,CACL,OAAO,CAAE,SAAS,CAClB,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,GAAG,CACR,IAAI,CAAE,GAAG,CACT,UAAU,CZ8BwB,OAAO,CY7BzC,KAAK,CAAE,IAAoB,CAC3B,OAAO,CAAE,QAA2C,CACtD,2CAA0B,CACxB,MAAM,CAAE,iBAA6B,CACrC,aAAa,CdcqB,IAAI,CcZ1C,+GAAmC,CACjC,MAAM,CAAE,iBAA6B,CACrC,OAAO,CAAE,GAAG,CACZ,UAAU,CAAE,IAAI,CAChB,UAAU,CZY0B,IAAM,CYV1C,MAAM,CAAE,YAAyB,CACjC,gLAAuB,CACrB,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,CAAC,CAEb,+BAA+B,CAC7B,KAAK,CAAE,IAAI,CACb,cAAc,CACZ,YAAY,CAAE,iBAA0C,CACxD,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZoByB,wMAAQ,CYnB5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,KAAK,CdI+B,OAAwB,CcH9D,2BAA2B,CACzB,WAAW,CAAE,GAAG,CAChB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,SAA2C,CACpD,WAAW,CZYyB,wMAAQ,CYX5C,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,GAAG,CAChB,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,IAAI,CACd,KAAK,CZnB+B,OAAW,CYuBjD,YAAY,CACV,2IAAgE,CAC9D,WAAW,CAAE,QAAQ,ECzDzB,IAAI,CACF,gBAAgB,CAAE,IAAO,CACzB,MAAM,CAAE,OAAO,CACf,OAAO,CAAE,MAAM,CACf,OAAO,CAAE,KAAK,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,IAAI,CACF,KAAK,CAAE,OAAO,CACd,gBAAgB,CAAE,OAAO,CAC3B,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,UAAU,CAAE,MAAM,CACpB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,MAAM,CACJ,KAAK,CAAE,IAAO,CACd,gBAAgB,CAAE,IAAO,CAC3B,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,MAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,MAAM,CACf,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CACd,WAAW,CAAE,IAAI,CACnB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,WAAW,CAAE,IAAI,CACnB,EAAE,CACA,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,OAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAI,CACb,GAAG,CACD,KAAK,CAAE,IAAO,CAChB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,OAAO,CCjJ3B,kBAAkB,CAChB,OAAO,CAAE,YAAY,CACrB,uCAAsB,CACpB,KAAK,CAAE,KAAK,CACd,oBAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAG,CACZ,gCAAa,CACX,YAAY,CAAE,CAAC,CACnB,6FAAI,CACF,OAAO,CAAE,GAAG,CACZ,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CAChB,qHAAS,CACP,KAAK,CdkB2B,OAAW,CcjBjD,qBAAqB,CACnB,aAAa,CAAE,CAAC,CAChB,KAAK,CdkB+B,OAAW,CcjB/C,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,YAAY,CbanB,oCAAsB,CaTxB,qBAAqB,CACnB,OAAO,CAAE,IAAI,CACf,uCAAuC,CACrC,OAAO,CAAE,IAAI,EAEjB,YAAY,CACV,uCAAuC,CACrC,OAAO,CAAE,IAAI,EC9BjB,SAAS,CACP,QAAQ,CAAE,KAAK,CACf,GAAG,CCAO,OAAO,CDGjB,gBAAO,CACL,eAAe,CAAE,IAAI,CAEzB,cAAc,C/B+FZ,KAAK,CAAE,CAAC,CACR,0CAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,oBAAO,CACL,KAAK,CAAE,IAAI,C+BnGb,mCAAM,CACJ,OAAO,CAAE,YAAY,CACvB,uBAAQ,CACN,UAAU,CAAE,qBAAoB,CAEhC,6BAAa,CACX,WAAW,CAAE,iBAAyB,CACxC,8BAAc,CACZ,YAAY,CAAE,iBAAyB,CAC3C,gBAAC,CACC,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,MAAiB,CAE9B,iBAAiB,CACf,KAAK,CjBuD+B,KAAK,CiBtDzC,oDAAiB,CACf,MAAM,CAAE,IAAmB,CAC3B,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAmB,CAChC,OAAO,CAAE,SAAS,CAClB,aAAa,CAAE,CAAC,CAChB,OAAO,CAAE,KAAK,CACd,WAAW,CAAE,IAAI,CACjB,cAAc,CAAE,SAAS,CACzB,SAAS,CAAE,GAAG,CACd,KAAK,CfZ6B,IAAK,CeavC,WAAW,CAAE,MAAM,CAErB,oBAAE,CACA,aAAa,CAAE,CAAC,CAEhB,+BAAY,CACV,UAAU,CAAE,iBAAyB,CACvC,kCAAe,CACb,aAAa,CAAE,iBAAyB,CAC1C,4BAAS,CACP,UAAU,CAAE,OAA4C,CACxD,8BAAC,CACC,KAAK,CfhByB,IAAY,CeiB1C,YAAY,CAAE,iBAAsD,CACpE,OAAO,CAAE,gBAAyB,CAClC,oCAAO,CACL,UAAU,CAAE,OAA4C,CAC9D,mGAAI,CACF,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,OAAO,CACnB,KAAK,CAAE,OAAO,CACd,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAElB,wCAAmB,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,IAAI,CACX,WAAW,CAAE,MAAM,CAGnB,SAAS,CAAE,KAAI,CACf,WAAW,CAAE,KAAK,CAClB,KAAK,CAAE,OAA8B,CAGzC,wDAAuB,CACrB,KAAK,Cf1C6B,OAAW,Ce2C7C,OAAO,CAAE,gBAAmB,CAC5B,WAAW,CAAE,IAAI,CACjB,QAAQ,CAAE,QAAQ,CAClB,UAAU,CfrCwB,OAAyB,CesC3D,MAAM,CAAE,IAAI,CACZ,aAAa,CAAE,iBAAsD,CACrE,UAAU,CAAE,iBAAsD,CAClE,YAAY,CAAE,YAAY,CAE1B,oEAAO,CACL,UAAU,Cf5CsB,OAAyB,Ce6CzD,4GAAmB,CACjB,KAAK,CfrDyB,IAAY,CesD9C,gGAAmB,CAGjB,OAAO,CAAE,KAAK,CACd,SAAS,CAAE,KAAI,CACf,WAAW,CAAE,KAAK,CAClB,KAAK,CAAE,IAA8B,CAIvC,iHAAI,CACF,OAAO,CAAE,IAAI,CACf,iIAAc,CACZ,OAAO,CAAE,KAAK,CAGd,yCAAG,CACD,UAAU,CAAE,OAA4C,CACxD,OAAO,CAAE,gBAAyB,CACpC,uDAAiB,CACf,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,OAA4C,CACxD,OAAO,CAAE,gBAAyB,CACtC,2DAA2B,CACzB,KAAK,Cf9E2B,IAAY,Ce+E9C,mDAAmB,CACjB,KAAK,CAAE,OAA4C,CACvD,+BAAa,CACX,SAAS,CAAE,KAAI,CAEb,yCAAG,CACD,UAAU,CAAE,OAA4C,CACxD,OAAO,CAAE,gBAAyB,CACpC,uDAAiB,CACf,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,OAA4C,CACxD,OAAO,CAAE,gBAAyB,CAClC,UAAU,CAAE,IAAI,CAChB,aAAa,CAAE,IAAI,CACvB,2DAA2B,CACzB,KAAK,Cf9F2B,IAAY,Ce+F9C,mDAAmB,CACjB,KAAK,CAAE,OAA4C,CACvD,+BAAa,CACX,SAAS,CAAE,KAAI,CAEjB,+BAAa,CACX,OAAO,CAAE,KAAK,CAChB,uBAAK,CACH,aAAa,CAAE,CAAC,CAChB,OAAO,CAAE,IAAI,CAEb,kCAAK,CACH,OAAO,CAAE,KAAK,CAClB,4BAAU,CACR,aAAa,CAAE,CAAC,CAChB,KAAK,Cf7G6B,OAAW,Ce8G7C,WAAW,CAAE,MAAM,CACrB,mBAAC,CACC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,gBAAmB,CAC5B,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,GAAG,CACd,KAAK,CftH6B,OAAW,CeuH7C,yBAAO,CACL,gBAAgB,CAAE,OAAoC,CACtD,MAAM,CAAE,OAAO,CACf,6CAAmB,CACjB,KAAK,Cf3HyB,OAAW,Ce4H7C,0BAAQ,CACN,gBAAgB,CftHgB,OAAK,CeuHrC,MAAM,CAAE,OAAO,CACf,KAAK,Cf9H2B,IAAM,Ce+HtC,8CAAmB,CACjB,KAAK,CfhIyB,IAAM,CekI5C,mBAAmB,CACjB,OAAO,CAAE,KAAK,CACd,KAAK,CjBvF+B,KAAK,CiBwFzC,OAAO,CAAE,OAAW,CACpB,aAAa,CAAE,OAAW,CAC1B,OAAO,CjBrF6B,GAAG,CiBsFvC,gBAAgB,CflIoB,OAAK,CemIzC,UAAU,CAAE,MAAM,CAClB,OAAO,CAAE,OAAW,CACpB,OAAO,CAAE,KAAK,CACd,KAAK,CfvI+B,OAAyB,CewI7D,aAAa,CAAE,OAAW,CAC1B,oCAAgB,CACd,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,IAAI,CACnB,OAAO,CAAE,QAAQ,CACjB,YAAY,CAAE,OAAuB,CACvC,uBAAG,CACD,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,sBAA0B,CAClC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CflJkB,OAAK,CemJvC,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,wDAAqB,CACnB,KAAK,CfvJ6B,OAAyB,CewJ3D,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,OAA2C,CACpD,aAAa,CAAE,OAAW,CAE1B,oEAAO,CACL,UAAU,CAAE,qBAAoB,CAClC,0EAAQ,CACN,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,MAAM,CACd,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,aAAa,CAAE,CAAC,CAChB,SAAS,CAAE,IAAI,CACf,UAAU,CAAE,WAAa,CAEzB,oFAAQ,CACN,UAAU,CAAE,MAAM,CACxB,+BAAa,CACX,UAAU,CAAE,SAAkB,CAC9B,aAAa,CAAE,OAAW,CAC1B,WAAW,CAAE,MAAM,CACnB,KAAK,CAAE,qBAAoB,CAI7B,gCAAM,CACJ,KAAK,CfnL6B,OAAK,CeoLzC,2BAAC,CACC,KAAK,Cf5L6B,OAAW,Ce6L7C,iCAAO,CACL,gBAAgB,CfvLgB,OAAK,CewLrC,KAAK,Cf9L2B,IAAM,CegM5C,gBAAgB,CjC3NR,kBAAoB,CAAE,gBAAM,CAK5B,eAAiB,CAAE,gBAAM,CAezB,UAAY,CAAE,gBAAM,CiCyM1B,QAAQ,CAAE,QAAQ,CAClB,OAAO,CAAE,CAAC,CACV,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACV,4BAAa,CACX,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,OAAO,CAAE,CAAC,CACZ,0BAAW,CACT,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,KAAK,CACX,OAAO,CAAE,CAAC,CACZ,2BAAY,CACV,KAAK,CAAE,KAAK,CACZ,IAAI,CAAE,IAAI,CACV,OAAO,CAAE,CAAC,CAGd,gBAAgB,CACd,UAAU,CAAE,qBAAuC,CACnD,gBAAgB,CAAE,2uCAA2uC,CAC7vC,eAAe,CAAE,SAAsB,CAEzC,gBAAgB,CACd,QAAQ,CAAE,QAAQ,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEd,YAAY,CACV,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,cAAc,CAAE,GAAG,CACnB,KAAK,CjBvL+B,KAAK,CiBwLzC,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,IAAI,CAChB,UAAU,CfrO0B,OAAsB,CesO1D,OAAO,CjBvL6B,GAAG,CiByLzC,eAAe,CACb,KAAK,CAAE,KAAyB,CAChC,QAAQ,CAAE,QAAQ,CAClB,UAAU,CAAE,MAAM,CAClB,UAAU,CAAE,MAAM,CAClB,MAAM,CAAE,IAAI,CAEd,WAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,Cf9O0B,OAAK,Ce+OzC,KAAK,CfrP+B,IAAM,CesP1C,OAAO,CAAE,gBAAuB,CAChC,QAAQ,CAAE,QAAQ,CAClB,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,C/BvLf,KAAK,CAAE,CAAC,CACR,oCAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,iBAAO,CACL,KAAK,CAAE,IAAI,C+BmLb,aAAC,CACC,KAAK,Cf7P6B,IAAM,Ce8PxC,WAAW,CAAE,IAAI,CAEnB,eAAG,CACD,YAAY,CAAE,IAAqB,CACnC,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,Cf9PkB,OAAK,Ce+PvC,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,IAAI,CACrB,aAAC,CACC,SAAS,CAAE,IAAI,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,OAAO,CAEnB,oBAAoB,CAClB,WAAW,CjBhOyB,KAAK,CiBiOzC,UAAU,CfzQ0B,OAAyB,Ce0Q7D,UAAU,CAAE,IAAI,CAElB,eAAe,CACb,OAAO,CAAE,eAAmB,CAC5B,MAAM,CAAE,IAAI,CACZ,SAAS,CAAE,KAAK,CAChB,MAAM,CAAE,IAAI,CAEd,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,eAAc,CAC1B,OAAO,CAAE,IAAI,CACb,OAAO,CAAE,GAAkB,CAC3B,gBAAI,CACF,OAAO,CAAE,KAAK,CAClB,MAAM,CACJ,KAAK,CflT+B,IAAW,CemT/C,QAAC,CACC,aAAa,CAAE,IAAqB,CACtC,6FAAgB,CACd,OAAO,CAAE,GAAG,CACZ,WAAW,CfhRuB,wMAAQ,CeiR1C,SAAS,CAAE,GAAG,CACd,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,IAAI,CACZ,KAAK,Cf3T6B,IAAW,Ce6TjD,mBAAmB,C/BzOjB,KAAK,CAAE,CAAC,CACR,oDAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,yBAAO,CACL,KAAK,CAAE,IAAI,C+BuOb,0BAAU,CACR,aAAa,CjBrTqB,IAAI,CiBsTtC,aAAa,CAAE,iBAA6B,CAC5C,cAAc,CjBvToB,IAAI,CiBwTxC,sCAAsB,CACpB,UAAU,CAAE,iBAA6B,CACzC,WAAW,CjB1TuB,IAAI,CiB2TxC,4BAAY,CACV,SAAS,CAAE,IAAI,CACf,aAAa,CAAE,IAAqB,CACpC,OAAO,CAAE,YAAY,CACvB,wBAAQ,CACN,KAAK,Cf9T6B,IAAY,Ce+T9C,SAAS,CAAE,GAAG,CdjUd,oCAAsB,CcqUxB,gBAAgB,CACd,UAAU,Cf7TwB,OAAyB,Ce8T7D,WAAW,CACT,OAAO,CAAE,KAAK,CAChB,YAAY,CAER,IAAI,CAAE,MAAmB,CAG3B,kBAAO,CACL,KAAK,CAAE,GAAG,CACV,IAAI,CAAE,CAAC,CACX,eAAe,CACb,KAAK,CAAE,IAAI,CACb,mBAAmB,CACjB,KAAK,CAAE,IAAI,CACb,yBAAyB,CACvB,KAAK,CAAE,IAAI,CACb,oBAAoB,CAClB,WAAW,CAAE,CAAC,CACd,oCAAe,CACb,OAAO,CCxXD,OAAO,CDyXf,0BAAO,CACL,QAAQ,CAAE,KAAK,CACf,SAAS,CAAE,IAAI,CACf,IAAI,CAAE,GAAG,CACT,GAAG,CAAE,CAAC,CACN,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,MAAM,EdjWlB,qCAAsB,CcoWxB,oBAAoB,CAClB,UAAU,CAAE,gBAAe,CAC7B,eAAe,CACb,MAAM,CAAE,CAAC,CACT,UAAU,Cf/VwB,OAAyB,EeiW/D,YAAY,CACV,iCAAmC,CACjC,OAAO,CAAE,IAAI,CACf,oBAAoB,CAClB,WAAW,CAAE,CAAC,EE9YlB,aAAa,CACX,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,KAAK,CnB6E+B,KAAK,CmB5EzC,KAAK,CjBoC+B,OAAyB,CiBnC7D,UAAU,CAAE,OAAkC,CAC9C,UAAU,CAAE,kBAAiC,CAC7C,WAAW,CjB+CyB,uDAAM,CiB9C1C,OAAO,CnB+E6B,GAAG,CmB9EvC,eAAC,CACC,KAAK,CjB+B6B,OAAK,CiB9BvC,eAAe,CAAE,IAAI,CACvB,8BAAgB,CACd,OAAO,CAAE,IAAI,CACf,kCAAoB,CAClB,OAAO,CAAE,IAAqB,CAC9B,gBAAgB,CAAE,OAAkC,CACpD,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,KAAK,CACjB,SAAS,CAAE,GAAG,CACd,MAAM,CAAE,OAAO,CACf,KAAK,CjBX6B,OAAM,ChB4F1C,KAAK,CAAE,CAAC,CACR,kFAAS,CAEP,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,EAAE,CACb,wCAAO,CACL,KAAK,CAAE,IAAI,CiCrFX,uqDAAG,CACD,KAAK,CjBgB2B,OAAyB,CiBf3D,yFAAQ,CACN,KAAK,CAAE,IAAI,CACb,6CAAU,CACR,KAAK,CAAE,IAAI,CACb,kDAAiB,CACf,gBAAgB,CnBQgB,OAAI,CmBPpC,KAAK,CjBI2B,IAAM,CiBHxC,yDAAwB,CACtB,gBAAgB,CjBmBgB,OAAO,CiBlBvC,KAAK,CnBzB2B,IAAI,CmB0BxC,0CAA8B,CAC5B,OAAO,CAAE,KAAK,CAChB,iCAAmB,CACjB,SAAS,CAAE,GAAG,CACd,OAAO,CAAE,IAAqB,CAC9B,KAAK,CjBP6B,IAAY,CiBQ9C,OAAO,CAAE,IAAI,CACb,oCAAE,CACA,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,GAAG,CACX,MAAM,CAAE,CAAC,CACT,MAAM,CAAE,MAAM,CACd,OAAO,CAAE,CAAC,CACV,UAAU,CAAE,iBAA6C,CAC3D,oCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,CAAC,CACT,sCAAC,CACC,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,GAAqB,CAC9B,KAAK,CjBfyB,OAAyB,CiBgB7D,uBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,IAAI,CAAE,IAAI,CACV,MAAM,CAAE,IAAI,CACZ,SAAS,CnBkByB,KAAK,CmBjBvC,kCAAU,CACR,KAAK,CAAE,IAAI,CACb,mEAAQ,CACN,KAAK,CAAE,IAAI,CACb,qDAA+B,CAC7B,UAAU,CAAE,KAAK,CACjB,+HAAQ,CACN,KAAK,CAAE,IAAI,CACb,gEAAU,CACR,KAAK,CAAE,IAAI,CACf,4CAAoB,CAClB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAChC,OAAO,CAAE,KAAK,CACd,UAAU,CAAE,MAAM,ChBhDpB,oCAAsB,CgBmDxB,aAAa,CACX,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,IAAI,CACb,mBAAO,CACL,OAAO,CAAE,KAAK,CAClB,GAAG,CACD,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,ECzEd,gBAAG,CACD,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,eAAe,CAEzB,uBAAU,CACR,aAAa,CpBUqB,IAAI,CoBTtC,iCAAS,CACP,UAAU,CAAE,MAAM,CAEtB,oCAAuB,CACrB,UAAU,CAAE,MAAM,CAGpB,qDAAoC,CAClC,aAAa,CpBCqB,IAAI,CoBUxC,uBAAU,CACR,WAAW,CpBXuB,IAAI,CoBYtC,WAAW,CpBZuB,IAAI,CoBatC,aAAa,CpBbqB,IAAI,CoBmBtC,kTAAK,CACH,aAAa,CAAE,CAAC,CAKlB,qCAAQ,CACN,YAAY,CAAE,GAAG,CAUrB,8BAAiB,CACf,YAAY,CAAE,eAAc,CAC5B,mEAAM,CACJ,UAAU,CAAE,sBAAsB,CAClC,YAAY,CAAE,0BAAyB,CAG3C,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CACzB,0EAAiD,CAC/C,UAAU,CAAE,WAAW,CAGzB,qDAA4B,CAC1B,aAAa,CAAE,IAAqB,CACtC,wBAAW,CACT,WAAW,CpBpDuB,IAAI,CoBuDxC,yBAAY,CACV,WAAW,CAAE,IAAI,CACjB,aAAa,CAAE,IAAqB,CACtC,yBAAY,CACV,KAAK,ClB3D6B,OAAW,CkB4D/C,yBAAY,CACV,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,iBAA2C,CACrD,wBAAW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,iBAA2C,CACrD,0BAAa,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,KAAK,CAMd,6RAAW,CACT,OAAO,CAAE,IAAI,CACb,UAAU,CAAE,MAAM,CAClB,SAAS,CAAE,IAAI,CAEf,mVAAO,CACL,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,GAAO,CAChB,WAAW,CAAE,WAAW,CACxB,OAAO,CAAE,YAAY,CACzB,mVAAmB,CACjB,OAAO,CAAE,YAAY,CAGzB,qBAAQ,CACN,KAAK,CAAE,KAAK,CACZ,KAAK,CAAE,GAAG,CACV,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,aAAuC,CAC/C,OAAO,CpB7F2B,IAAI,CoB8FtC,UAAU,ClB9EwB,OAAmB,CkB+ErD,MAAM,CAAE,iBAA+B,CAEvC,yEAAS,CACP,SAAS,CAAE,GAAG,CAChB,2BAAK,CACH,aAAa,CAAE,CAAC,CAClB,oCAAc,CACZ,OAAO,CAAE,KAAK,CACd,WAAW,ClB/EqB,0DAAa,CkBgF7C,WAAW,CAAE,IAAI,CACjB,UAAU,ClBvFsB,OAAmB,CkBwFnD,OAAO,CAAE,QAA2C,CACpD,MAAM,CAAE,KAAkB,CAC1B,aAAa,CpB5GmB,IAAI,CoB6GpC,SAAS,CAAE,IAAI,CAEnB,yBAAY,CACV,UAAU,ClB3FwB,OAAO,CkB4FzC,OAAO,CAAE,YAAY,CACrB,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,KAAuB,CAGlC,iEAAwC,CACtC,cAAc,CAAE,KAAK,CACrB,SAAS,CAAE,GAAG,CAIhB,yEAAgD,CAC9C,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,IAAI,CACZ,KAAK,ClB5I6B,IAAW,CkB6I7C,+JAAM,CACJ,MAAM,CAAE,IAAI,CACZ,gBAAgB,CAAE,sBAAsB,CACxC,WAAW,CAAE,MAAM,CACrB,2FAAQ,CACN,YAAY,CAAE,CAAC,CACf,aAAa,CAAE,CAAC,CAChB,cAAc,CAAE,GAAG,CACrB,mKAAI,CACF,KAAK,ClBhJ2B,IAAK,CkBuJzC,6BAAgB,CAEd,MAAM,CAAE,IAAI,CACZ,gCAAE,CACA,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,GAAG,CAClB,uCAAW,CACT,OAAO,CAAE,YAAY,CACrB,UAAU,CAAE,GAAG,CACjB,yCAAW,CACT,aAAa,CAAE,IAAI,CACnB,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,MAAM,CACrB,yCAAW,CACT,UAAU,CAAE,IAAI,CAChB,YAAY,CAAE,CAAC,CAGnB,iDAAQ,CAEN,KAAK,CpB1L6B,IAAI,CoB2LtC,OAAO,CAAE,OAAO,CAChB,wHAAO,CACL,SAAS,CAAE,eAAe,CAC1B,WAAW,CAAE,MAAM,CAErB,yEAAS,CACP,KAAK,CpBpK2B,OAAI,CoBqKtC,wHAAW,CACT,WAAW,CAAE,IAAI,CACjB,KAAK,ClB9K2B,OAAW,CkBgL/C,uDAAY,CACV,KAAK,ClBvK6B,OAAK,CkBwKzC,eAAE,CACA,aAAa,CpBnLqB,IAAI,CoBoLtC,kBAAE,CACA,WAAW,CAAE,IAAI,CAEnB,6EAAgB,CACd,aAAa,CAAE,eAAgC,CAEjD,kBAAE,CACA,MAAM,CAAE,aAA4C,CAMxD,8BAAiB,CACf,aAAa,CpBlMqB,IAAI,CoBoMtC,iCAAE,CACA,OAAO,CAAE,YAAY,CACrB,MAAM,CAAE,KAAuB,CAC/B,SAAS,CAAE,GAAG,CACd,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,OAA0B,CACtC,KAAK,ClBhM2B,OAAK,CkBiMrC,UAAU,CAAE,iBAAoC,CAChD,OAAO,CAAE,GAAqB,CAC9B,QAAQ,CAAE,QAAQ,CAClB,wCAAQ,CACN,KAAK,CAAE,OAA0B,CACnC,6CAAW,CACT,KAAK,ClBjNyB,OAAW,CkBkNzC,SAAS,CAAE,eAAe,CAE9B,oCAAK,CACH,aAAa,CAAE,GAAqB,CACpC,MAAM,CAAE,IAAI,CACZ,WAAW,CAAE,cAAuB,CACpC,UAAU,CAAE,OAAa,CACzB,KAAK,ClBhO2B,IAAK,CkBiOrC,gDAAW,CACT,KAAK,ClB3NyB,OAAW,CkB4NzC,SAAS,CAAE,eAAe,CAC9B,6CAAc,CACZ,UAAU,CAAE,CAAC,CAEf,uGAAQ,CACN,WAAW,CAAE,IAAI,CACjB,oRAA2B,CACzB,gBAAgB,CAAE,WAAW,CAC7B,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,CAAC,CACV,SAAS,CAAE,eAAe,CAC5B,kIAAU,CACR,WAAW,CAAE,IAAI,CAErB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,OAAO,CAAE,KAAK,CACd,KAAK,CpBnQ2B,IAAI,CoBoQpC,WAAW,CAAE,IAAI,CACnB,wCAAS,CACP,OAAO,CAAE,YAAY,CACrB,aAAa,CAAE,GAAG,CAEtB,uDAA8B,CAC5B,OAAO,CAAE,YAAY,CACrB,KAAK,ClB1Q6B,OAAM,CkB2QxC,SAAS,CAAE,GAAG,CACd,YAAY,CpBvPsB,IAAI,CoBwPxC,2BAAc,CACZ,OAAO,CAAE,KAAK,CACd,KAAK,CAAE,KAAK,CACd,qBAAQ,CACN,aAAa,CAAE,IAAI,CACnB,WAAW,CAAE,IAAI,CAEnB,mDAAa,CACX,UAAU,CAAE,OAAO,CACnB,OAAO,CAAE,OAAO,CAChB,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,KAAK,CAAE,OAAO,CACd,MAAM,CAAE,OAAO,CACf,WAAW,CAAE,OAAO,CAIlB,mGAAQ,CACN,YAAY,CAAE,GAAG,CjB3QrB,oCAAsB,CiBgRtB,qBAAQ,CACN,KAAK,CAAE,IAAI,ECjTjB,wBAAwB,CACtB,KAAK,CnB+B+B,OAAW,CmB7BjD,KAAK,CACH,UAAU,CAAE,MAAM,YCHlB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,0GAAoB,YAGzB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,yGAAyB,YAG9B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,6FAAqB,YAG1B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,oFAAkB,YAGvB,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,gHAA4B,YAGjC,WAAW,CAAE,aAAa,CAC1B,UAAU,CAAE,MAAM,CAClB,WAAW,CAAE,GAAG,CAChB,GAAG,CAAE,uGAAyB",
"sources": ["../../../bower_components/neat/app/assets/stylesheets/grid/_grid.scss","../../../bower_components/bourbon/dist/addons/_prefixer.scss","../../../bower_components/wyrm/sass/wyrm_core/_reset.sass","../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/font-awesome/scss/_path.scss","../../../bower_components/font-awesome/scss/_core.scss","../../../bower_components/font-awesome/scss/_larger.scss","../../../bower_components/font-awesome/scss/_fixed-width.scss","../../../bower_components/font-awesome/scss/_list.scss","../../../bower_components/font-awesome/scss/_variables.scss","../../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../../bower_components/font-awesome/scss/_spinning.scss","../../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../../bower_components/font-awesome/scss/_mixins.scss","../../../bower_components/font-awesome/scss/_stacked.scss","../../../bower_components/font-awesome/scss/_icons.scss","../../../bower_components/wyrm/sass/wyrm_core/_font_icon_defaults.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../bower_components/wyrm/sass/wyrm_core/_alert.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss","../../../bower_components/wyrm/sass/wyrm_core/_button.sass","../../../bower_components/wyrm/sass/wyrm_core/_dropdown.sass","../../../bower_components/wyrm/sass/wyrm_core/_form.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_outer-container.scss","../../../bower_components/neat/app/assets/stylesheets/settings/_grid.scss","../../../bower_components/neat/app/assets/stylesheets/grid/_span-columns.scss","../../../bower_components/wyrm/sass/wyrm_core/_neat_extra.sass","../../../bower_components/wyrm/sass/wyrm_core/_generic.sass","../../../bower_components/wyrm/sass/wyrm_core/_table.sass","../../../bower_components/wyrm/sass/wyrm_core/_type.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments.sass","../../../bower_components/wyrm/sass/wyrm_addons/pygments/_pygments_light.sass","../../../sass/_theme_breadcrumbs.sass","../../../sass/_theme_layout.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_private.scss","../../../sass/_theme_badge.sass","../../../sass/_theme_rst.sass","../../../sass/_theme_mathjax.sass","../../../sass/_theme_font_local.sass"],
diff --git a/example_jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb b/example_jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb
new file mode 100644
index 0000000..6715b7a
--- /dev/null
+++ b/example_jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb
@@ -0,0 +1,1014 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9465e40",
+ "metadata": {},
+ "source": [
+ "
INDEX
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "Scripts related to BIOS
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7eaa85e8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change BIOS Settings | \n",
+ " Update BIOS Settings for iLO server | \n",
+ " PATCH | \n",
+ " BIOS_changeSettings | \n",
+ "
\n",
+ " \n",
+ " | BIOS Default | \n",
+ " Update BIOS to default setting | \n",
+ " POST | \n",
+ " BIOS_revertToDefault | \n",
+ "
\n",
+ " \n",
+ " | Set bios password | \n",
+ " Change bios password for HPE iLO system | \n",
+ " PATCH | \n",
+ " set_bios_password | \n",
+ "
\n",
+ " \n",
+ " | Set bios ISCSI | \n",
+ " Setting an ISCSI boot instance for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_bios_iscsi | \n",
+ "
\n",
+ " \n",
+ " | Get base registry | \n",
+ " Gathering base registry Data for HPE iLO Systems | \n",
+ " GET | \n",
+ " get_base_registry | \n",
+ "
\n",
+ " \n",
+ " | Get BIOS Settings | \n",
+ " Retrieving bios settings from iLO servers | \n",
+ " GET | \n",
+ " get_bios_settings | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b01ddc4e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "Scripts related to Users and Sessions
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1f075a76",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Add User Account | \n",
+ " Add new user account | \n",
+ " POST | \n",
+ " add_user_account | \n",
+ "
\n",
+ " \n",
+ " | Manually Managing Sessions With Redfish | \n",
+ " creates a new session with an iLO server | \n",
+ " POST | \n",
+ " sessions | \n",
+ "
\n",
+ " \n",
+ " | Delete User Account | \n",
+ " delete user account | \n",
+ " DELETE | \n",
+ " delete_user_account | \n",
+ "
\n",
+ " \n",
+ " | Modify User Account | \n",
+ " Modify an iLO user account on the server | \n",
+ " GET,PATCH | \n",
+ " modify_user_account | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9f91683a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e16cdec",
+ "metadata": {},
+ "source": [
+ "Scripts related to Booting
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616fef86",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change Boot Order | \n",
+ " Change iLOs boot ordert | \n",
+ " PATCH | \n",
+ " change_boot_order | \n",
+ "
\n",
+ " \n",
+ " | Change Temporary Boot Order | \n",
+ " Change iLOs temporary boot ordert | \n",
+ " PATCH | \n",
+ " change_temp_boot_order | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "317bbec4",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "387dc1d0",
+ "metadata": {},
+ "source": [
+ "Scripts related to Enterprise Secure Key Manager (ESKM)
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5f1b24c1",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Test ESKM Connection | \n",
+ " Script for testing connection to the ESKM system for HPE iLO systems | \n",
+ " POST | \n",
+ " test_ESKM_connection | \n",
+ "
\n",
+ " \n",
+ " | Gathering ESKM Data | \n",
+ " Collecting ESKM (Enterprise Secure Key Manager) data for HPE iLO | \n",
+ " GET | \n",
+ " get_ESKM | \n",
+ "
\n",
+ " \n",
+ " | Set ESKM Primary Key | \n",
+ " Configure the ESKM key server for HPE iLO systems | \n",
+ " POST | \n",
+ " set_ESKM_PrimaryKeyServer | \n",
+ "
\n",
+ " \n",
+ " | Set ESKM Username and Password | \n",
+ " Set the ESKM (Enterprise Secure Key Manager) username, password, and other configurations for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_ESKM_username_pass | \n",
+ "
\n",
+ " \n",
+ " | reset ESKM eventlog | \n",
+ " reset the ESKM (Enterprise Secure Key Manager) event log using the iLO API | \n",
+ " POST | \n",
+ " ESKM_eventlog | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c53f260c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acef9e30",
+ "metadata": {},
+ "source": [
+ "Scripts related to Firmware and Flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bfe4eeac",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Upload Firmware to iLO repository | \n",
+ " Script for uploading firmware to the iLO Repository for flashing | \n",
+ " POST | \n",
+ " upload_firmware_to_iLO_repo | \n",
+ "
\n",
+ " \n",
+ " | Upload Firmware with associated COMPSIG file to iLO repository | \n",
+ " Script for uploading a firmware component with a size less than\n",
+ "32 GB, and associated Component Signature (compsig) signature file to the iLO Repository | \n",
+ " POST | \n",
+ " Upload_fw_iLO_Repo_COMPSIG | \n",
+ "
\n",
+ " \n",
+ " | Update Firmware | \n",
+ " Script for updating Firmware via HTTP URL | \n",
+ " POST | \n",
+ " update_iLO_firmware | \n",
+ "
\n",
+ " \n",
+ " | View Firmware Inventory | \n",
+ " Script for viewing the firmware inventory on HPE iLO systems | \n",
+ " GET | \n",
+ " software_firmware_inventory | \n",
+ "
\n",
+ " \n",
+ " | Uploading Firmware to the iLO Repository For Flashing | \n",
+ " uploads firmware to a specified location using the Redfish API and HTTP POST request | \n",
+ " GET | \n",
+ " software_firmware_inventory | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7f3245b7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "774d4dc2",
+ "metadata": {},
+ "source": [
+ "Scripts related to iLO License
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6d7cc2f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set License Key\t | \n",
+ " Setting License Key | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Get License Key | \n",
+ " Retrieve iLO License Key for HPE iLO Systems | \n",
+ " GET | \n",
+ " get_license_key | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "87a754d8",
+ "metadata": {},
+ "source": [
+ "Scripts related to reset iLO
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b37a713",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | reset ilo | \n",
+ " reset the ilo using the iLO API | \n",
+ " POST | \n",
+ " reset_ilo | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d4473c5",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "473638bc",
+ "metadata": {},
+ "source": [
+ "Scripts related to Virtual Media
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39e6d1c2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Mount Virtual Media Iso\t | \n",
+ " obtain the virtual media information. | \n",
+ " PATCH | \n",
+ " mount_virtual_media_iso | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0299c78c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f1fc753",
+ "metadata": {},
+ "source": [
+ "Scripts related to SNMP
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ff18cb9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Configure SNMP | \n",
+ " Configuring SNMP for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp | \n",
+ "
\n",
+ " \n",
+ " | Configure SNMP trap source | \n",
+ " Configuring SNMP trap source for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp_trap_source | \n",
+ "
\n",
+ " \n",
+ " | Set SNMP alert destination | \n",
+ " Setting SNMP alert destination for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_snmp_alert | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a184d9af",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e43c3e0c",
+ "metadata": {},
+ "source": [
+ "Scripts related to Smart Array Storage
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "519adbf2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Smart Array Encryption Settings On HPE ILO Systems\t | \n",
+ " retrieves encryption settings for Smart Storage Array Controllers from a Redfish service. | \n",
+ " PATCH | \n",
+ " SmartArray_Encryption | \n",
+ "
\n",
+ " \n",
+ " | Logic drive | \n",
+ " Retrieves information about the smart array logical drive | \n",
+ " GET | \n",
+ " get_logical_drive | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "33d2d8b7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77acbc7f",
+ "metadata": {},
+ "source": [
+ "Scripts related to Managing Server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7dd28f1e",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Computer Details | \n",
+ " Get all the available computer/hosts details in iLO\t | \n",
+ " GET | \n",
+ " computer_details | \n",
+ "
\n",
+ " \n",
+ " | Set Server Asset Tag | \n",
+ " Setting server asset tag\t | \n",
+ " PATCH | \n",
+ " set_server_asset_tag | \n",
+ "
\n",
+ " \n",
+ " | Set UID Light | \n",
+ " Setting UID Light | \n",
+ " PATCH | \n",
+ " set_uid_light | \n",
+ "
\n",
+ " \n",
+ " | reset the server | \n",
+ " reset the server using the ilo API | \n",
+ " GET,POST | \n",
+ " reset_server | \n",
+ "
\n",
+ " \n",
+ " | Reboot the server | \n",
+ " reboot the server using the iLO API | \n",
+ " GET,POST | \n",
+ " reboot_server | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0528100d",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "60ecf170",
+ "metadata": {},
+ "source": [
+ "Scripts related to Security Certificate
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "df148ae0",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Enable_Secure_Boot\t | \n",
+ " obtain the secure boot information | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Generating a certificate signing request for HPE iLO systems¶ | \n",
+ " using resource_instances variable to obtain information about the resource directory by using get_resource_directory module. | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Issusing the certificate | \n",
+ " import an SSL certificate to the iLO | \n",
+ " Post | \n",
+ " import_ssl | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a961c65",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6e78323",
+ "metadata": {},
+ "source": [
+ "Scripts related to NTP and Timezone
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf265e66",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set iLO NTP Server | \n",
+ " Setting NTP Servers for HPE iLO Systems | \n",
+ " PATCH | \n",
+ " set_ilo_ntp_servers | \n",
+ "
\n",
+ " \n",
+ " | Set iLO Timezone | \n",
+ " Setting the timezone for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_ilo_ntp_timezone | \n",
+ "
\n",
+ " \n",
+ " | Enable Ntp Servers | \n",
+ " enable NTP servers for HPE ilo systems | \n",
+ " PATCH | \n",
+ " enabling_ntp_server | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d3afe833",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "57663508",
+ "metadata": {},
+ "source": [
+ "Scripts related to Network and NIC
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb76ce7b",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get iLO IP | \n",
+ " Retrieve the IP address of an HPE iLO server | \n",
+ " GET | \n",
+ " get_ilo_ip | \n",
+ "
\n",
+ " \n",
+ " | Get iLO nic | \n",
+ " Retrieve the network interface card (NIC) configuration of the iLO server. | \n",
+ " PATCH | \n",
+ " get_ilo_nic | \n",
+ "
\n",
+ " \n",
+ " | Set Ethernet Management | \n",
+ " Set the static IP configuration for the Manager ethernet interface of an HPE iLO system | \n",
+ " GET | \n",
+ " set_ethernet_management | \n",
+ "
\n",
+ " \n",
+ " | Find ilo Mac Address | \n",
+ " finding ilo mac address related information | \n",
+ " GET | \n",
+ " find_ilo_mac_address | \n",
+ "
\n",
+ " \n",
+ " | Setting the active Manager NIC | \n",
+ " used to enable/disable Ethernet interfaces on an iLO | \n",
+ " GET | \n",
+ " get_license_key | \n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7cea8664",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "456e00fb",
+ "metadata": {},
+ "source": [
+ "Scripts related to AHS, Syslog and IML
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c073eebe",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Clear AHS data | \n",
+ " Clear active health state data of iLO server | \n",
+ " DELETE | \n",
+ " clear_ahs_data | \n",
+ "
\n",
+ " \n",
+ " | Set remote syslog server\t | \n",
+ " Setting Remote syslog Server for an HPE iLO management processor. | \n",
+ " PATCH | \n",
+ " set_syslogserver | \n",
+ "
\n",
+ " \n",
+ " | Clear iLO IEL IML log\t | \n",
+ " Clearing out the iLO event log and management log at server side | \n",
+ " DELETE | \n",
+ " clear_ilo_iel_iml_log | \n",
+ "
\n",
+ " \n",
+ " | Get AHS Data | \n",
+ " Collecting Active Health System data of iLO systems. | \n",
+ " GET | \n",
+ " get_ahs_data | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "594b46a2",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7d88adab",
+ "metadata": {},
+ "source": [
+ "Scripts related to Redfish operation and utility
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71299947",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Quickstart Redfish | \n",
+ " Interact with iLO using REDFISH for system information | \n",
+ " GET | \n",
+ " quickstart_redfish | \n",
+ "
\n",
+ " \n",
+ " | ilorest_util | \n",
+ " Retrieves the resource directory from the server and Determines the generation and version of the iLO | \n",
+ " GET | \n",
+ " ilorest_util | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9dec363f",
+ "metadata": {},
+ "source": [
+ "Scripts related to Power
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b5fa53d4",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get Power Metrics Average | \n",
+ " Script for gathering the power metrics average on HPE iLO systems | \n",
+ " GET | \n",
+ " get_powermetrics_average | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d49853c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b445d67",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ecd072de",
+ "metadata": {},
+ "source": [
+ "Miscellaneous Scripts
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "87b872fd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Example Data Resopnses | \n",
+ " Example Script for expanding data responses | \n",
+ " GET | \n",
+ " expand_data | \n",
+ "
\n",
+ " \n",
+ " | System Schema Data | \n",
+ " retrieves the URI for the root JSON schema from the Redfish service object ( | \n",
+ " GET | \n",
+ " get_schema.ipynb | \n",
+ "
\n",
+ " \n",
+ " | Resource directory | \n",
+ " Retrieves the resource directory from an HPE server and also determines the generation and version of an iLO system | \n",
+ " GET | \n",
+ " resource_directory | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "da54fe5d",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/Jupyter1.mp4 b/example_jupyter_notebooks/Jupyter1.mp4
new file mode 100644
index 0000000..a17c639
Binary files /dev/null and b/example_jupyter_notebooks/Jupyter1.mp4 differ
diff --git a/example_jupyter_notebooks/Jupyter2.mp4 b/example_jupyter_notebooks/Jupyter2.mp4
new file mode 100644
index 0000000..08303b2
Binary files /dev/null and b/example_jupyter_notebooks/Jupyter2.mp4 differ
diff --git a/example_jupyter_notebooks/Reset Ilo/reset_ilo.ipynb b/example_jupyter_notebooks/Reset Ilo/reset_ilo.ipynb
new file mode 100644
index 0000000..a6b7d9d
--- /dev/null
+++ b/example_jupyter_notebooks/Reset Ilo/reset_ilo.ipynb
@@ -0,0 +1,267 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e2d7d850",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Resetting the Manager"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88f096f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
Resetting the Manager As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1525f25",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
ServerDownOrUnreachableError\n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "8ce9142d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9615aea",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our clear_ahs_data to function overview, in the end this will clear ahs data.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the resetting a manager function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. If the resource instance is not empty then the code fetches information about a manager from a collection of \"Managers\" resources on a target system, using a Redfish client object. It retrieves the first member's URI, and then gets more details about that specific member.\n",
+ "
\n",
+ "\n",
+ "3. Else i.e; then iterates through a collection of Redfish resource instances and checks if the type of each instance is #Manager. If it is, the code retrieves more information about that specific instance using the Redfish client object _redfishobj.\n",
+ "
\n",
+ "\n",
+ "4. If manager_members_respone is ture then it retrieves the URI for the Reset action on a specific Redfish manager using the managers_members_response variable, and then creates a request body containing the Action key with the value Manager.Reset. Finally, it sends a POSTrequest to the retrieved URI using the Redfish client object _redfishobj to initiate a reset operation on the target system.\n",
+ "
\n",
+ " 5.Next is to check the status of the response received from the previous POST request sent using the Redfish client object _redfishobj.\n",
+ "
\n",
+ " 1.If the status is 400, it attempts to print the extended error message associated with the response.\n",
+ "
\n",
+ " 2.If the response status is not 400 and not 200, an error message is printed to the standard error stream.\n",
+ "
\n",
+ " 3.If the response status is 200, it indicates that the reset operation was successful. The code then prints a success message and prints the JSON response received from the server in a formatted way.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "16042277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_ilo(_redfishobj, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " managers_members_response = None\n",
+ " \n",
+ " #function get_resource_directory returns Redfish resource instances from client object.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " #checking target resource is empty are not \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Manager.' in instance['@odata.type']:\n",
+ " managers_members_uri = instance['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " #checking the managers_members_response true or not\n",
+ " if managers_members_response:\n",
+ " reset_ilo_uri = managers_members_response.obj['Actions']['#Manager.Reset']['target']\n",
+ " body = {'Action': 'Manager.Reset'}\n",
+ " resp = _redfishobj.post(reset_ilo_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e7543eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call reset_ilofunction with two parameters redfish object,DISABLE_RESOURCE_DIR with our redfish object and rest the settings to default.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "270f99bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reset_ilo(REDFISHOBJ, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1557bfee",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e685a623",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ahs_syslog_iml/clear_ahs_data.ipynb b/example_jupyter_notebooks/ahs_syslog_iml/clear_ahs_data.ipynb
new file mode 100644
index 0000000..7239576
--- /dev/null
+++ b/example_jupyter_notebooks/ahs_syslog_iml/clear_ahs_data.ipynb
@@ -0,0 +1,253 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e2d7d850",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Clearing AHS data for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88f096f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Clearing AHS(Active Health System) data!!!\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to clear AHS data. This code is written in Python and uses the redfish library to perform the required operations.
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1525f25",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e15955c9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9615aea",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our clear_ahs_data to function overview, in the end this will clear ahs data.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
clear_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the Managers member's response object with different
odata_id we get a bios uri . Then again an http GET request is made and response is stored in
active_health_system_response.\n",
+ " Then we set the
active_health_system_clear_log_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else if the resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set
active_health_system_uri and
get active_health_system_response settings of the user through redfish object and then then set the path to post the action of clearing ahs data that we will perform.\n",
+ "
\n",
+ "\n",
+ "5. We will post the
active_health_system_clear_log_uri and the body to the Redfish Client through Redfish Object\n",
+ "\n",
+ " Ultimately if the operation was successful without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16042277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ahs_data(_redfishobj):\n",
+ "\n",
+ " active_health_system_clear_log_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response.obj['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " break\n",
+ "\n",
+ " if active_health_system_clear_log_uri:\n",
+ " body = {\"Action\": \"HpeiLOActiveHealthSystem.ClearLog\"}\n",
+ " resp = _redfishobj.redfish_client.post(active_health_system_clear_log_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e7543eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "
\n",
+ " \n",
+ "2. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call clear_ahs_data with our redfish object and rest the settings to default.
\n",
+ "
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1557bfee",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "270f99bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ahs_data(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e685a623",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb b/example_jupyter_notebooks/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb
new file mode 100644
index 0000000..2534c6b
--- /dev/null
+++ b/example_jupyter_notebooks/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "89dc5655",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Clear iLO Logs
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "898cbb84",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
for clearing out the iLO event log and management log at server side! As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98f3c2dd",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "935d8f7c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ef3013ef",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This cell gives overview about of the function used to clear event logs such as IML and IEL logs.
\n",
+ "The IML provides a record of historical events that have occurred on the server and the IEL is the iLO event log provides record of significant events detected by iLO.\n",
+ " \n",
+ "1. When the resource directory is disabled then we simply navigate through the API for obtaining the relevant uri.\n",
+ " The series of HTTP get requests aims to extracts log_services_response so as to get the path of the directory for which IEL and IML logs need to be cleared.\n",
+ "
\n",
+ "2. Else if the resource directory enabled then rather we can simply extract the uri by #LogService.attribute inside the instance['odatatype'] dictionary and again make a HTTP get request to obtain the required uri.\n",
+ "
\n",
+ "3. After obtaining the uri we just need to make changes on the same location using a post request so as to clear IEL and IML logs successfully. For this body dictionary contains the attribute to be changed and IEL/IML are searched in the path of clear_log_services_uri and the respective changes are made by redfishobj.post(path,body).\n",
+ "
\n",
+ " \n",
+ "4. Later we also check for the response returned by the server side. If the response is anything outside of status code with 200 then error message gets rendered on the webpage else the success message is printed out with the response dictionary returned by the server.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "a7abae2a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ilo_event_log(_redfishobj, clear_IML_IEL):\n",
+ "\n",
+ " clear_log_services_uri = []\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " log_services_uri = systems_members_response.obj['LogServices']['@odata.id']\n",
+ " log_services_response = _redfishobj.get(log_services_uri)\n",
+ " log_services_uris = log_services_response.obj['Members']\n",
+ " for log_services_uri in log_services_uris:\n",
+ " log_services_response = _redfishobj.get(log_services_uri['@odata.id'])\n",
+ " clear_log_services_uri.append(log_services_response.obj['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#LogService.' in instance['@odata.type']:\n",
+ " log_service_uri = instance['@odata.id']\n",
+ " clear_log_services_uri.append(_redfishobj.get(log_service_uri).dict['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ "\n",
+ " if clear_log_services_uri:\n",
+ " body = {\"Action\": \"LogService.ClearLog\"}\n",
+ " for path in clear_log_services_uri:\n",
+ " if (\"IEL\" in clear_IML_IEL and \"IEL\" in path) or (\"IML\" in clear_IML_IEL and \\\n",
+ " \"IML\" in path):\n",
+ " if \"IEL\" in path:\n",
+ " sys.stdout.write(\"Clearing IEL log.\\n\")\n",
+ " else:\n",
+ " sys.stdout.write(\"Clearing IML log.\\n\")\n",
+ " resp = _redfishobj.post(path, body)\n",
+ " else:\n",
+ " continue\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "331b8289",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. The Main function
\n",
+ "The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ " \n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "4. If server is down or Unreachable we get server not reachable message!
\n",
+ "5. Else if no error is encountered a function call is made i.e. clear_ilo_event_log(REDFISHOBJ, CLEAR_IEL_IML)that is responsible for handling clearing all the IEL and IML logs at the server side.
\n",
+ "6. Lastly, REDFISHOBJ.logout logs us out of the system and ends the session.\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f120e784",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4143942b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ " CLEAR_IML_IEL = \"IML\" # provide either the string IML or IEL\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ilo_event_log(REDFISHOBJ, CLEAR_IML_IEL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f702c0ae",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ahs_syslog_iml/get_ahs_data.ipynb b/example_jupyter_notebooks/ahs_syslog_iml/get_ahs_data.ipynb
new file mode 100644
index 0000000..e7a75e5
--- /dev/null
+++ b/example_jupyter_notebooks/ahs_syslog_iml/get_ahs_data.ipynb
@@ -0,0 +1,266 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b765efae",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Gathering AHS Data for HPE iLO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63436786",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "97ddcec7",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "61eea7c2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dd7bf36c",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2. This is our ahs gathering data function overview, in the end we will get the Active Health System data.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
get_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about the Active Health System is stored inside the
managers json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the ahs data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object with different
odata_id we get the managers members uri .\n",
+ " Then again an http GET request is made and response is stored in
managers_response_response.\n",
+ " Then we set the
active_health_system_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeiLOActiveHealthSystem attribute is present in
@odata.type attribute then we'll set active_health_system_uri and
get active_health_system_log_resp through redfish object.\n",
+ "
\n",
+ "\n",
+ "5. If this is successful, then we will open a
logfile and write
active_health_system_log_resp.ori which is the get_ahs_data to that logfile.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ahs_data(_redfishobj, logfile=\"data.ahs\"):\n",
+ "\n",
+ " active_health_system_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ "\n",
+ " if active_health_system_uri:\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_log_uri = active_health_system_response.obj.Links['AHSLocation']\\\n",
+ " ['extref']\n",
+ " active_health_system_log_resp = _redfishobj.get(active_health_system_log_uri)\n",
+ " if active_health_system_log_resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(active_health_system_log_resp.obj['error']\\\n",
+ " ['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif active_health_system_log_resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % active_health_system_log_resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " with open(logfile, 'wb') as ahsoutput:\n",
+ " ahsoutput.write(active_health_system_log_resp.ori)\n",
+ " ahsoutput.close()\n",
+ " sys.stdout.write(\"AHS Data saved successfully as: \\'%s\\'\" % logfile)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ec57c0d8",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter ilo url,username,password, and the path of log file
\n",
+ " \n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_ahs_data with our redfish object and logfile.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3cd9f29b",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # logfile path and filename\n",
+ " LOGFILE = input(\"Enter log file path and file name: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ahs_data(REDFISHOBJ, LOGFILE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "df024e0c",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ahs_syslog_iml/set_syslogserver.ipynb b/example_jupyter_notebooks/ahs_syslog_iml/set_syslogserver.ipynb
new file mode 100644
index 0000000..6c82b25
--- /dev/null
+++ b/example_jupyter_notebooks/ahs_syslog_iml/set_syslogserver.ipynb
@@ -0,0 +1,283 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b92b79fb",
+ "metadata": {},
+ "source": [
+ "Setting remote syslog server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ed959e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Setting remote syslog server\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to set remote syslog server. This code is written in Python and uses the redfish library to perform the required operations.
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a91bf91",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
ilorest_util\n",
+ "
argparse \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6eed1f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6393e74d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our set_syslog function overview
\n",
+ " This function sets the remote syslog server and enables remote syslog on an iLO system.
\n",
+ "1. It takes two parameters:\n",
+ "
\n",
+ " - _redfishobj: an object representing the connection to the iLO device through the Redfish API.
\n",
+ " - syslog_server: a string representing the IP address or hostname of the remote syslog server.
\n",
+ "2. The function first retrieves the model information of the system, which is used to determine the Oem (Original equipment manufacturer) name, as the endpoint structure and payload might differ based on the manufacturer. It determines the model of the server by sending a GET request to the
/redfish/v1/Systems/1/ URI and extracting the
Model attribute from the response.
\n",
+ "3. It checks if the model contains \"Gen9\" or \"Gen8\". If either of them is present, it sets the \"hp\" variable to \"Hp\". Otherwise, it sets it to \"Hpe\".
\n",
+ "4. It then constructs the URI for the syslog configuration resource and sends a PATCH request with the request body to set the remote syslog server and enable remote syslog.
\n",
+ " 5. Finally, it calls the
ilo_response, passing the
_redfishobj and
resp (response) as arguments. This function handles response from the server.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2971240e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_syslog(_redfishobj, syslog_server):\n",
+ "\n",
+ " model_uri = \"/redfish/v1/Systems/1/\"\n",
+ " model = _redfishobj.get(model_uri).obj['Model']\n",
+ " print (model)\n",
+ " if \"Gen9\" in model or 'Gen8' in model:\n",
+ " hp = \"Hp\"\n",
+ " else:\n",
+ " hp = \"Hpe\"\n",
+ "\n",
+ " syslog_uri = \"/redfish/v1/Managers/1/NetworkService/\"\n",
+ "\n",
+ " body = {\"Oem\": {hp: {\"RemoteSyslogServer\": syslog_server, \"RemoteSyslogEnabled\": True}}}\n",
+ " resp = _redfishobj.patch(syslog_uri, body)\n",
+ " ilo_response(_redfishobj, resp)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1fdc6d56",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is ilo_response function overview
\n",
+ " The ilo_response function is responsible for handling the response from the iLO server.
\n",
+ "1. It takes two parameters: _redfishobj (Redfish client object) and resp (response object).
\n",
+ "2. It checks the status code of the response. If it is equal to 400, it indicates a client error.
\n",
+ "3. It tries to extract and print the extended error information from the response using the key error ['@Message.ExtendedInfo'].\n",
+ "If there is an exception while accessing the extended error information, it writes an error message to the standard error stream.
\n",
+ "4. If the status code is not 400 but is not equal to 200 either, it indicates an HTTP response error.\n",
+ "It writes an error message to the standard error stream, indicating the HTTP response status.
\n",
+ "5. If the status code is 200, it indicates a successful response.\n",
+ "It prints the message \"Success\" to indicate the operation was successful.
\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b2db998f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ilo_response(_redfishobj, resp):\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d95a2d40",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "1. An argument parser is initialized to parse the command-line arguments passed to the script. The parser expects arguments such as iLO url, username, password, and syslog server IP.
\n",
+ "2.The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "3. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "5. The get_gen function is called to retrieve the iLO generation number of the server.\n",
+ " Depending on the iLO generation number, the set_syslog function is called with the Redfish client object and the syslog server IP address.
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "750b6ae8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3681c0d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-s',\n",
+ " '--syslog_server',\n",
+ " dest='syslog_server',\n",
+ " action=\"store\",\n",
+ " required=True,\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " set_syslog(redfish_obj, options.syslog_server)\n",
+ " else:\n",
+ " set_syslog(redfish_obj, options.syslog_server)\n",
+ " redfish_obj.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f91c6419",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/bios/BIOS_ChangeSettings.ipynb b/example_jupyter_notebooks/bios/BIOS_ChangeSettings.ipynb
new file mode 100644
index 0000000..f9f4268
--- /dev/null
+++ b/example_jupyter_notebooks/bios/BIOS_ChangeSettings.ipynb
@@ -0,0 +1,278 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "25002fd3",
+ "metadata": {},
+ "source": [
+ "Change BIOS Settings
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6a14567a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b0a99221",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bb04ead1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8505c876",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change bios settings function overview, in the end this will be able to change the bios settings.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
change_bios_settings function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a BIOS URI .\n",
+ " Then again an http GET request is made and response is stored in
systems_response.\n",
+ " Then we set the systems_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e., resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios data of the user through redfish object. Now we will get the bios_settings_uri through bios_data object.\n",
+ "
\n",
+ "\n",
+ "5. Then if bios password is present, then we will update the bios password. Finally we will send
patch request from redfish object using
bios_setting_uri. \n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then we will get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "243405a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_bios_setting(_redfishobj, bios_property, property_value, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if bios_uri:\n",
+ " #BIOS settings URI is needed\n",
+ " \n",
+ " bios_settings_uri = bios_data.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " body = {'Attributes': {bios_property: property_value}}\n",
+ " \n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " resp = _redfishobj.patch(bios_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " #uncomment if you would like to see the full list of attributes\n",
+ " #print(\"\\n\\nShowing BIOS attributes after changes:\\n\\n\")\n",
+ " #bios_data = _redfishobj.get(bios_uri)\n",
+ " #print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2c62673d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Please enter iLO url, username, password, bios attribute, attribute_value and bios password when asked.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_bios_settings with our redfish object and the attribute we need and change and the value along with the bios password.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1f44368d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14547cd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = getpass.getpass(\"Enter bios password: \")\n",
+ " \n",
+ " #provide the attribute name and the associated attribute value. Note: some, values may\n",
+ " #be containers (arrays or dictionaries) so keep this in mind.\n",
+ " \n",
+ " ATTRIBUTE = input(\"Enter bios property you wish to change (Example: AdminName): \")\n",
+ " ATTRIBUTE_VAL = input(\"Enter Value of the property to change (Example: Luigi): \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_bios_setting(REDFISHOBJ, ATTRIBUTE, ATTRIBUTE_VAL, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91b6f3c6",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/bios/BIOS_RevertToDefault.ipynb b/example_jupyter_notebooks/bios/BIOS_RevertToDefault.ipynb
new file mode 100644
index 0000000..461f4d2
--- /dev/null
+++ b/example_jupyter_notebooks/bios/BIOS_RevertToDefault.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ad9eed9d",
+ "metadata": {},
+ "source": [
+ "Reverting the BIOS to it's default values
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bdc5c94",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b6adafee",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2c1c9a1c",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "# Import the required libraries\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "# Import the helper function\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "397110c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a HTTP
GET operation and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an HTTP GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "91157e79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bios_revert_default(_redfishobj):\n",
+ " # Initialize the BIOS reset action URI (Uniform Resource Identifier)\n",
+ " bios_reset_action_uri = None\n",
+ " \n",
+ " # Get the resource directory to find the relevant URI\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " # If resource directory is not available or not to be used, find the relevant URI\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " # Get the systems URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " \n",
+ " # Get the systems members URI\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " \n",
+ " # Get the BIOS URI\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " \n",
+ " # Get the BIOS reset action URI\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " # Use resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ " \n",
+ " # Define the body for the POST request\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType': 'default'}\n",
+ " \n",
+ " # Send the POST request\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ " \n",
+ " # Check the response status\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b26b9819",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9886e56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fbdb430d",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " # Call the function to revert BIOS to default values\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ "\n",
+ " # Logout from the Redfish client\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f8583d9",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/bios/get_base_registry.ipynb b/example_jupyter_notebooks/bios/get_base_registry.ipynb
new file mode 100644
index 0000000..70bb2ae
--- /dev/null
+++ b/example_jupyter_notebooks/bios/get_base_registry.ipynb
@@ -0,0 +1,207 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a58ca6e6",
+ "metadata": {},
+ "source": [
+ "Gathering base registry Data for HPE iLO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7c0b9464",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4c85742",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f7d14ed",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
2. Below is the get_base_registry function. The get_base_registry function serves the purpose of retrieving the base registry information from an HPE iLO server using the HPE iLO REST API.
\n",
+ " It performs the following steps to accomplish this:
\n",
+ "1. The get_base_registry function sends a GET request to the /rest/v1/Registries endpoint of the HPE iLO server to retrieve the registry data.\n",
+ "
\n",
+ "2. It iterates through the response entries, checking for the \"Id\" field or extracting the schema name.\n",
+ "
\n",
+ "3. For each entry, it makes additional GET requests to the specified URIs to retrieve the registry information.\n",
+ "
\n",
+ "4. If successful, it displays a message and stores the registry messages in a dictionary. The function returns the dictionary containing the registry messages.\n",
+ "
\n",
+ "In summary, the get_base_registry function retrieves the base registry information by making requests to specific URIs, extracting relevant data, and storing it for further analysis and management.\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_base_registry(restobj):\n",
+ " response = restobj.get(\"/rest/v1/Registries\")\n",
+ " messages = {}\n",
+ "\n",
+ " identifier = None\n",
+ "\n",
+ " for entry in response.dict[\"Items\"]:\n",
+ " if \"Id\" in entry:\n",
+ " identifier = entry[\"Id\"]\n",
+ " else:\n",
+ " identifier = entry[\"Schema\"].split(\".\")[0]\n",
+ "\n",
+ " if identifier not in [\"Base\", \"iLO\"]:\n",
+ " continue\n",
+ "\n",
+ " for location in entry[\"Location\"]:\n",
+ " reg_resp = restobj.get(location[\"Uri\"][\"extref\"])\n",
+ "\n",
+ " if reg_resp.status == 200:\n",
+ " sys.stdout.write(\"\\tFound \" + identifier + \" at \" + \\\n",
+ " location[\"Uri\"][\"extref\"] + \"\\n\")\n",
+ " messages[identifier] = reg_resp.dict[\"Messages\"]\n",
+ " else:\n",
+ " sys.stdout.write(\"\\t\" + identifier + \" not found at \"\\\n",
+ " + location[\"Uri\"][\"extref\"] + \"\\n\")\n",
+ "\n",
+ " return messages"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ccb21ff7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
3. This is the main function overview.
\n",
+ "The following code establishes a connection to an HPE iLO server using the HPE iLO REST API.
- It sets up the necessary parameters for either local or remote server connection.
- It creates a REST client object, logs into the iLO server, executes an example function to retrieve registry information, and logs out from the server.
This code showcases how to interact with the iLO server programmatically, demonstrating the usage of the HPE iLO REST API for server management tasks.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "89c773e0",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 2: Find and return registry \" + \"\\n\")\n",
+ " get_base_registry(REST_OBJ)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e3ba41a7",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/bios/get_bios_settings.ipynb b/example_jupyter_notebooks/bios/get_bios_settings.ipynb
new file mode 100644
index 0000000..16de568
--- /dev/null
+++ b/example_jupyter_notebooks/bios/get_bios_settings.ipynb
@@ -0,0 +1,247 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Getting BIOS Settings
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
2. Below is the get_bios_settings function, after everything is done this function will give details about bios settings of system.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
get_bios_setting function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In case the resource directory was disabled we are using systems making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings.
- For that purpose simply we are making series of get requests.
\n",
+ " We make a final get operation by at the location bios_uri and save the response inside bios_data.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately, if bios_data variable is not null we print out information about bios settings. \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_bios_setting(_redfishobj):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing bios attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
3. The Main function:
\n",
+ "
\n",
+ " - Once your credentials are entered, a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable, we get server not reachable message!
\n",
+ " - If not, then we make a call to get_bios_settings function to obtain information about bios settings of system.
\n",
+ " - After getting required information Redfish.logout()closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Enter iLO IP address: 10.0.2.15\n",
+ "Enter Username: Administrator\n",
+ "Enter password: 12iso*help\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 13\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 12\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 13\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 14\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 15\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 17\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 16\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 17\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 18\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 19\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_bios_setting(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/example_jupyter_notebooks/bios/set_bios_iscsi.ipynb b/example_jupyter_notebooks/bios/set_bios_iscsi.ipynb
new file mode 100644
index 0000000..a3b7cef
--- /dev/null
+++ b/example_jupyter_notebooks/bios/set_bios_iscsi.ipynb
@@ -0,0 +1,242 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a036d81b",
+ "metadata": {},
+ "source": [
+ "Setting an ISCSI boot instance for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0ffb0a82",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library Here is an example to
set an ISCSI boot instance for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " Also do run each succesive cell of code \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc60fabf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "62e0ead3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d2c00edc",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. Below is a set_bios_iscsi that sets the ISCSI boot instance for HPE iLO systems.
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. The function takes two parameters:
_redfishobj (a Redfish client object) and
iscsi_properties (a dictionary containing the iSCSI properties to be set).
\n",
+ "2. It calls the
get_resource_directory function to obtain the resource directory from the Redfish service. If
DISABLE_RESOURCE_DIR is set to True or the resource directory is empty, the code retrieves the necessary URIs manually.
\n",
+ "3.
If the resource directory is disabled or not available, the code fetches the systems URI and retrieves the
BIOS URI from the response. The code retrieves the
iSCSI URI from the BIOS response and fetches the
iSCSI data.
\n",
+ "4.
If the resource directory is enabled and available, the code iterates over the instances in the resource directory and searches for the iSCSI instance based on its type.
\n",
+ "5.
If the iSCSI data is found, the code loops over the iSCSI sources and checks if the iSCSIBootInstance property matches the current index. If a match is found, the code updates the iSCSI properties for that instance.
\n",
+ "6. The code sends a
PATCH request to the iSCSI URI with the updated iSCSI sources data.
\n",
+ "7. If the response status is 400, indicating an error, the code attempts to print the error message. If the response status is not 200 or 201, an error message is printed.
\n",
+ "8. If the response status is 200, the code indicates success and suggests that a system reboot will be required to apply the changes. It also prints the response details.
\n",
+ "\n",
+ "The loop is broken after processing the desired iSCSI instance.\n",
+ "
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f6bfe14a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_bios_iscsi(_redfishobj, iscsi_properties):\n",
+ "\n",
+ " iscsi_uri = None\n",
+ " iscsi_data = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " iscsi_uri = bios_response.obj.Oem.Hpe.Links['iScsi']['@odata.id']\n",
+ " iscsi_data = _redfishobj.get(iscsi_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiSCSISoftwareInitiator.' in instance['@odata.type']:\n",
+ " iscsi_uri = instance['@odata.id']\n",
+ " iscsi_data = _redfishobj.get(iscsi_uri)\n",
+ "\n",
+ " if iscsi_data:\n",
+ " for indx, inst in enumerate(iscsi_data.obj['iSCSISources']):\n",
+ " if iscsi_properties['iSCSIBootInstance'] == indx:\n",
+ " iscsi_data.dict['iSCSISources'][indx].update(iscsi_properties)\n",
+ " resp = _redfishobj.patch(iscsi_uri, {'iSCSISources' : iscsi_data.dict['iSCSISources']})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the\n",
+ " #iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], \\\n",
+ " indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " print(json.dumps(resp.ori, indent=4, sort_keys=True))\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \" \\\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! A system reboot will be required to complete the change.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "55289e4d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - We are passing the required information to change the password of iLO user account i.e. base_url, username, password
\n",
+ " - If server is down or Unreachable we get server not reachable message.
\n",
+ " - The set_bios_iscsi function is called, passing the RedfishClient object (REDFISHOBJ) and the iSCSI properties dictionary (ISCSI_PROPERTIES).
\n",
+ "\n",
+ "- After setting the iSCSI properties, the logout method of the RedfishClient object is called to end the session with the server.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9b5acb64",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11b07dec",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ " \n",
+ " #iscsi properties\n",
+ " ISCSI_PROPERTIES = {\"iSCSIBootInstance\": 2, \\\n",
+ " \"iSCSITargetName\": \"Target\", \\\n",
+ " \"iSCSIAttemptName\": \"Empty\", \\\n",
+ " \"iSCSIConnectRetry\": 5}\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_bios_iscsi(REDFISHOBJ, ISCSI_PROPERTIES)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1c7d1d0b",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/bios/set_bios_password.ipynb b/example_jupyter_notebooks/bios/set_bios_password.ipynb
new file mode 100644
index 0000000..bcfc647
--- /dev/null
+++ b/example_jupyter_notebooks/bios/set_bios_password.ipynb
@@ -0,0 +1,248 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "d357d38b",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Setting Bios Password
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fce7e904",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library Here is an example to
change bios password for HPE iLO system!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " Also do run each succesive cell of code \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a89aa82f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8cf61dff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "828be423",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. Below is the set_bios_password function, through which we can change the password of bios system.
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
set_bios_setting function we are taking three parameters i.e.
Redfish object,
new_password and exisiting password as
bios_password. Also
resource_instances variable is being obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
If the resource directory was disabled we are making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings and later make changes to the existing password.
- For that purpose simply we are making series of get requests.
\n",
+ " - After navigating through iLO rest api we actually save the http address of location where bios settings are present inside bios_uri
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3.
Else if the resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "4.
If bios_uri is not null after making above operations, we can perform the required actions to change the bios password.
\n",
+ " - Following up we make get request and obtain the URL of the location where we are actually going to make the changes.
- Ultimately, we make a post request by passing the bios_change_pass_uri and body dictionary that contains the changes made to the password.
\n",
+ " - The job of post request here is to update the password at the provided location and send a response whether the job was done properly or not.
\n",
+ " \n",
+ " If the reponse status code was anything other than 200 or 201 then we can print out the response status code and error message.
\n",
+ " Else we print out success message with the response obtained after making post request.\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "ee515d74",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_bios_password(_redfishobj, new_password, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_uri:\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_change_pass_uri = bios_data.obj['Actions']['#Bios.ChangePassword']['target']\n",
+ " body = dict()\n",
+ " body[\"PasswordName\"] = \"Administrator\"\n",
+ " body[\"OldPassword\"] = bios_password\n",
+ " body[\"NewPassword\"] = new_password\n",
+ " resp = _redfishobj.post(bios_change_pass_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b93c0d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - We are passing the required information to change the password of iLO user account i.e. base_url, username, password
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Once everything is done you are automatically logged out.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "34f69788",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38b9fd3a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #new BIOS password\n",
+ " NEW_BIOS_PASSWORD = \"password\"\n",
+ " #old BIOS password\n",
+ " OLD_BIOS_PASSWORD = \"password\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_bios_password(REDFISHOBJ, NEW_BIOS_PASSWORD, OLD_BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71f23513",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/boot/Change_Boot_Order.ipynb b/example_jupyter_notebooks/boot/Change_Boot_Order.ipynb
new file mode 100644
index 0000000..6ff5922
--- /dev/null
+++ b/example_jupyter_notebooks/boot/Change_Boot_Order.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e8359fe6",
+ "metadata": {},
+ "source": [
+ "Change Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8cb46c69",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6557d8e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9dc3d6d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7753861c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change boot order function overview, in the end this will change the boot order by one position.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. This function initializes bios_boot_uri and bios_boot_response variables to None.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find bios_boot_uri. If bios_boot_uri is not None, retrieve the BIOS boot settings using get() method. Then Retrieve the URI for BIOS boot settings from the response.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "4. If bios_password is provided, update the BIOS password with it.\n",
+ "
\n",
+ "\n",
+ "5. Print the current boot order. Rotate the first boot device to the end of the boot order. Update the boot order using the patch() method with the new boot order.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated BIOS boot settings.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9740789",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_boot_order(_redfishobj, bios_password):\n",
+ "\n",
+ " bios_boot_uri = None\n",
+ " bios_boot_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_boot_uri = bios_response.obj.Oem.Hpe.Links.Boot['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeServerBootSettings.' in instance['@odata.type']:\n",
+ " bios_boot_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_boot_uri:\n",
+ " bios_boot_response = _redfishobj.get(bios_boot_uri)\n",
+ " #Bios boot settings URI is needed\n",
+ " bios_boot_settings_uri = bios_boot_response.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " sys.stdout.write(\"Rotating the first boot device to the end of the boot order.\\n\")\n",
+ " sys.stdout.write('Current Order:\\n')\n",
+ " boot_order = bios_boot_response.obj['DefaultBootOrder']\n",
+ " for indx, boot_device in enumerate(boot_order):\n",
+ " sys.stdout.write('Pos ' + str(indx) + ' : ' + boot_device + '\\n')\n",
+ " device = boot_order.pop(0)\n",
+ " sys.stdout.write(\"Rotating device: \\'%s\\' to the end of the boot order.\\n\" % device)\n",
+ " boot_order.append(device)\n",
+ "\n",
+ " body = {'DefaultBootOrder': boot_order}\n",
+ " resp = _redfishobj.patch(bios_boot_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! Your system may need to be restarted.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"Unable to find Boot Order URI.\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17889355",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_boot_order function with our redfish object and BIOS Password as parameters
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "73d96a09",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cba1616",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = None\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_boot_order(REDFISHOBJ, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f00caf4",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/boot/Change_Temp_Boot_Order.ipynb b/example_jupyter_notebooks/boot/Change_Temp_Boot_Order.ipynb
new file mode 100644
index 0000000..9337b80
--- /dev/null
+++ b/example_jupyter_notebooks/boot/Change_Temp_Boot_Order.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a9b0b4a",
+ "metadata": {},
+ "source": [
+ "Change Temporary Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04e1b75",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f33ca630",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0058d42d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d69021c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change temporary boot order function overview, in the end this will set the boot order temporarily to the device stored in \"boottarget\" variable.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ " \n",
+ "2. This function first calls get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find systems_members_uri where we can set the temporary boot target. If systems_members_uri is not None, then set the attribute 'BootSourceOverrideTarget' to 'boottarget' varible.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated boot override target.\n",
+ " \n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aaba46fd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_temporary_boot_order(_redfishobj, boottarget):\n",
+ "\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))\n",
+ " body = {'Boot': {'BootSourceOverrideTarget': boottarget}}\n",
+ " resp = _redfishobj.patch(systems_members_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing boot override target:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2405f770",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the temporary boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of _REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "4. When asked to enter Temporary Boot Device, enter desired temporary boot device (Example: Hdd)
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Then we call change_temporary_boot_order function with our redfish object and chosen temporary boot device as parameters
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4d5f0843",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b43b7a95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # string to represent the selected temporary boot device\n",
+ " TEMP_DEVICE = input(\"Enter temporary boot device: \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_temporary_boot_order(REDFISHOBJ, TEMP_DEVICE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9784ce2a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/get_ESKM.ipynb b/example_jupyter_notebooks/eskm/get_ESKM.ipynb
new file mode 100644
index 0000000..3816800
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/get_ESKM.ipynb
@@ -0,0 +1,224 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ad50a3f3",
+ "metadata": {},
+ "source": [
+ "Gathering ESKM Data for HPE iLO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "095bee7c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b052d673",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f95f3667",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ed3ca1cf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. The purpose of the get_ESKM function is to retrieve Enterprise Secure Key Manager (ESKM) data from an HPE iLO (Integrated Lights-Out) system. It requires a connection to the iLO system through the Redfish API.
\n",
+ " Here's a step-by-step breakdown of what the function does:\n",
+ "
\n",
+ "- It starts by initializing a variable called security_service_eskm_uri, which will store the URI (Uniform Resource Identifier) for the ESKM service.\n",
+ "
- \n",
+ "Next, the function uses the get_resource_directory function to obtain the list of available resource instances from the Redfish service. This helps in discovering the necessary URIs.\n",
+ "
- \n",
+ "If the DISABLE_RESOURCE_DIR flag is set or there are no resource instances available, an alternative approach is taken to find the relevant URI. The function navigates through the Redfish resource hierarchy to locate the URI for the security service associated with the iLO system.\n",
+ "
- \n",
+ "Once the security service URI is obtained, the function retrieves the ESKM URI from the response. This URI points to the specific ESKM resource within the HPE server.\n",
+ "
- \n",
+ "If the resource directory is available, the function iterates through the resource instances to find the URI with the identifier '#HpeESKM.' This identifier indicates the presence of the ESKM resource.\n",
+ "
- \n",
+ "If a valid ESKM URI is found, the function makes a GET request to retrieve the ESKM data using the Redfish client object (_redfishobj).\n",
+ "
\n",
+ "Finally, the fetched ESKM data is printed in a nicely formatted JSON representation, providing the necessary information about the ESKM configuration.\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "902eb516",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ESKM(_redfishobj):\n",
+ "\n",
+ " security_service_eskm_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " security_service_eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " security_service_eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if security_service_eskm_uri:\n",
+ " security_service_eskm_resp = _redfishobj.get(security_service_eskm_uri)\n",
+ " print(json.dumps(security_service_eskm_resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f840454b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is the Main function overview.
\n",
+ "
\n",
+ "
- It sets up the connection parameters, including the server URL, login credentials, and a flag for enabling the resource directory feature.\n",
+ "
- It creates a RedfishClient object using the connection parameters and logs in to the server.\n",
+ "
- If the server is unreachable or does not support the Redfish protocol, it displays an error message and exits the script.\n",
+ "
- It calls the get_ESKM function to retrieve and print the ESKM data from the HPE iLO system.\n",
+ "
- Finally, it logs out from the server, ending the session.\n",
+ "
In summary, the main function establishes a connection with the HPE server, retrieves ESKM data, and ensures a clean logout from the server.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f2e371fe",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally, use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e37b7ca5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ESKM(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/reset_ESKM_eventlog.ipynb b/example_jupyter_notebooks/eskm/reset_ESKM_eventlog.ipynb
new file mode 100644
index 0000000..1ac340b
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/reset_ESKM_eventlog.ipynb
@@ -0,0 +1,378 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7d4d890e",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reset_ESKM_eventlog"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "62aaa233",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
resetting the ESKM event log (ESKM stand for Enterprise Secure Key Manager) As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fbfec992",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish\n",
+ "
RedfishClient\n",
+ "
ServerDownOrUnreachableError\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "ee51abfe",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Defaulting to user installation because normal site-packages is not writeable\n",
+ "Collecting redfish\n",
+ " Downloading redfish-3.1.9-py3-none-any.whl (40 kB)\n",
+ "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m40.5/40.5 KB\u001b[0m \u001b[31m1.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25hCollecting jsonpatch\n",
+ " Downloading jsonpatch-1.32-py2.py3-none-any.whl (12 kB)\n",
+ "Requirement already satisfied: jsonpointer in /home/tanveer/.local/lib/python3.10/site-packages (from redfish) (2.3)\n",
+ "Collecting requests-toolbelt\n",
+ " Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)\n",
+ "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 KB\u001b[0m \u001b[31m6.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+ "\u001b[?25hRequirement already satisfied: requests in /usr/lib/python3/dist-packages (from redfish) (2.25.1)\n",
+ "Collecting jsonpath-rw\n",
+ " Downloading jsonpath-rw-1.4.0.tar.gz (13 kB)\n",
+ " Preparing metadata (setup.py) ... \u001b[?25ldone\n",
+ "\u001b[?25hCollecting requests-unixsocket\n",
+ " Downloading requests_unixsocket-0.3.0-py2.py3-none-any.whl (11 kB)\n",
+ "Requirement already satisfied: decorator in /home/tanveer/.local/lib/python3.10/site-packages (from jsonpath-rw->redfish) (5.1.1)\n",
+ "Requirement already satisfied: ply in /usr/lib/python3/dist-packages (from jsonpath-rw->redfish) (3.11)\n",
+ "Requirement already satisfied: six in /usr/lib/python3/dist-packages (from jsonpath-rw->redfish) (1.16.0)\n",
+ "Building wheels for collected packages: jsonpath-rw\n",
+ " Building wheel for jsonpath-rw (setup.py) ... \u001b[?25ldone\n",
+ "\u001b[?25h Created wheel for jsonpath-rw: filename=jsonpath_rw-1.4.0-py3-none-any.whl size=15149 sha256=adb33a2925919ff914e1e8d37078e269f133f5a20afb9ba6d09a5f3a2cb743b7\n",
+ " Stored in directory: /home/tanveer/.cache/pip/wheels/e3/76/6f/c25be6a9e6cc9985b96e8c95997d46790242c6426ef68e754c\n",
+ "Successfully built jsonpath-rw\n",
+ "Installing collected packages: requests-unixsocket, requests-toolbelt, jsonpath-rw, jsonpatch, redfish\n",
+ "Successfully installed jsonpatch-1.32 jsonpath-rw-1.4.0 redfish-3.1.9 requests-toolbelt-1.0.0 requests-unixsocket-0.3.0\n",
+ "Note: you may need to restart the kernel to use updated packages.\n"
+ ]
+ }
+ ],
+ "source": [
+ "pip install redfish"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "9688b9d5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Defaulting to user installation because normal site-packages is not writeable\n",
+ "Collecting redfish-client\n",
+ " Downloading redfish_client-0.3.9-py2.py3-none-any.whl (13 kB)\n",
+ "Requirement already satisfied: requests>=2.16 in /usr/lib/python3/dist-packages (from redfish-client) (2.25.1)\n",
+ "Installing collected packages: redfish-client\n",
+ "Successfully installed redfish-client-0.3.9\n",
+ "Note: you may need to restart the kernel to use updated packages.\n"
+ ]
+ }
+ ],
+ "source": [
+ "pip install redfish-client"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "9b53ecf2",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ImportError",
+ "evalue": "cannot import name 'RedfishClient' from 'redfish' (/home/tanveer/.local/lib/python3.10/site-packages/redfish/__init__.py)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01msys\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mredfish\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m RedfishClient\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mredfish\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mrest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mv1\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ServerDownOrUnreachableError\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mget_resource_directory\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m get_resource_directory\n",
+ "\u001b[0;31mImportError\u001b[0m: cannot import name 'RedfishClient' from 'redfish' (/home/tanveer/.local/lib/python3.10/site-packages/redfish/__init__.py)"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b8c9efd9",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
Below is the overview of reset_ESKM_eventlog function. In this function we are providing secure management of cryptographic keys for various purposes for example encryption and authentication.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present for secure key manager.\n",
+ "\n",
+ "1. In the function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "2. If the resource directory is enabled or we want to force it's non-use then navigate to the directory where managers members data is present. \n",
+ " Utilising the HPE (Hewlett Packard Enterprise) OEM Redfish implementation to retrieve the URI for the ESKM (Enterprise Security Key Manager) service.\n",
+ " By making a Redfish API call to reset the event log of the HPE Enterprise Secure Key Manager (ESKM) security service of an HPE server. It first tries to obtain the URI for the ESKM service using the HPE-specific resource directory, but if that is not available or disabled, it falls back to navigating the Redfish API object model to find the necessary URIs for the relevant managers and security service.\n",
+ " Once the URI for the ESKM service is obtained, a POST request is sent to the ClearESKMLog action using the post() method of the Redfish API object, with an empty dictionary in the body of the request.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "3. Else It iterates through a list of resource instances and checks if the instance type contains #HpeESKM in it. If found, it sets the URI of that resource instance as the ESKM URI and breaks out of the loop. \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "4. If above function retrive the URI for the ESKM service from the HPE-specific Links object then we retrieves the URI for a specific action to clear the ESKM log on an HPE server's Security Service ESKM resource, using the Redfish API. It then sets the action to be executed on the server in the request body.\n",
+ " \n",
+ "
\n",
+ " \n",
+ " If the response of this POST request was 400 it means there was some error from server-side while doing the same operation and we inform the user about the error by It attempts to extract and pretty-print the extended error message information, but if this fails, it writes an error message to the standard error stream indicating that it was unable to access the iLO Extended Message Info.\n",
+ "
\n",
+ " Else there can also be an error which we aren't aware of, in that case we print out the response status code alongwith erro message .
\n",
+ " Ultimately, if everything went properly we print out the response object along with success message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "93003c6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_ESKM_eventlog(_redfishobj):\n",
+ "\n",
+ " body = dict()\n",
+ " security_service_eskm_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " security_service_eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " security_service_eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if security_service_eskm_uri:\n",
+ " security_service_eskm_uri = _redfishobj.get(security_service_uri).obj.Links\\\n",
+ " ['ESKM']['@odata.id']\n",
+ " security_service_eskm_resp = _redfishobj.get(security_service_eskm_uri)\n",
+ " security_service_eskm_clearlog_uri = security_service_eskm_resp.obj['Actions']\\\n",
+ " ['#HpeESKM.ClearESKMLog']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.ClearESKMLog\"\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(security_service_eskm_clearlog_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a583e0e",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient object is being created mainly to log into the system with valid credentials.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "3. We try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "4. Then we call reset_ESKM_eventlogfunction with our redfish object and the function does the reset the ESKM_eventlog.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "\n",
+ "5. Lastly, REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "85745d7d",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reset_ESKM_eventlog(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "69132144",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ea6fce6f",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/set_ESKM_PrimaryKeyServer (2).ipynb b/example_jupyter_notebooks/eskm/set_ESKM_PrimaryKeyServer (2).ipynb
new file mode 100644
index 0000000..7c760bb
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/set_ESKM_PrimaryKeyServer (2).ipynb
@@ -0,0 +1,296 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Set_ESKM_PrimaryKeyServer
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
set_ESKM_PrimaryKeyServer As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about set_ESKM_PrimaryKeyServer function
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "1. This function sets the primary key server for the HPE ESKM service.
\n",
+ "
\n",
+ " \n",
+ "2. It takes three arguments: _redfishobj (an object representing the Redfish service), primary_key_server_address (a string representing the IP address or hostname of the primary key server), and primary_key_server_port (an integer representing the port number of the primary key server).
\n",
+ "
\n",
+ "\n",
+ "3. It uses the get_resource_directory function to find the relevant ESKM URI, which is used to make a POST request to set the primary key server.
\n",
+ "
\n",
+ "\n",
+ "4. If the POST request is successful (returns an HTTP status code of 200), the function prints a success message and the JSON response from the server.
\n",
+ "
\n",
+ "5. If the POST request is unsuccessful, the function prints an error message and, if available, the extended error information from the server response.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ESKM_PrimaryKeyServer(_redfishobj, primary_key_server_address, primary_key_server_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ "\n",
+ " body[\"PrimaryKeyServerAddress\"] = primary_key_server_address\n",
+ " body[\"PrimaryKeyServerPort\"] = int(primary_key_server_port)\n",
+ "\n",
+ " resp = _redfishobj.post(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " PRIMARY_KEY_SERVER_ADDRESS = \"192.168.1.1\"\n",
+ " PRIMARY_KEY_SERVER_PORT = \"9000\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ESKM_PrimaryKeyServer(REDFISHOBJ, PRIMARY_KEY_SERVER_ADDRESS, PRIMARY_KEY_SERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/set_ESKM_username_pass.ipynb b/example_jupyter_notebooks/eskm/set_ESKM_username_pass.ipynb
new file mode 100644
index 0000000..bd6bd11
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/set_ESKM_username_pass.ipynb
@@ -0,0 +1,240 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "4b4e4b7d",
+ "metadata": {},
+ "source": [
+ "Setting the ESKM data for HPE iLO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c0e6c8ad",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cbce568c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9e2d3008",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "de961951",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ "
The code below defines a function called ESKM_username_pass that is responsible for configuring the ESKM (Enterprise Secure Key Manager) settings on an HPE iLO system using the Redfish API. The function takes several parameters, including the ESKM username, password, account group, primary key server address, and primary key server port.
\n",
+ "
The following steps explain this function:
\n",
+ "\n",
+ "1. Get the resource directory to find the URI for the ESKM service.\n",
+ "2. If the resource directory is not available or disabled, manually search for the relevant URI by navigating through the API hierarchy.\n",
+ "3. If the URI for the ESKM service is found, create a dictionary object with the login name, password, account group, ESKM local CA certificate name, primary key server address, and primary key server port.\n",
+ "4. Use the HTTP PATCH method to update the ESKM service configuration with the dictionary object.\n",
+ "5. Check the response status code to determine if the update was successful or if an error occurred. If there was an error, print the error message or status code. If the update was successful, print the response body.\n",
+ "
\n",
+ "The ESKM_username_pass function is used to configure the ESKM settings on an HPE iLO system. It retrieves the ESKM URI, populates the configuration data, sends a PATCH request to update the settings, and handles the response accordingly. Upon successful update, it prints a success message along with the response details.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38d43c16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ESKM_username_pass(_redfishobj, eskm_username, eskm_password, eskm_accountgroup, \\\n",
+ " eskm_primarykeyserver_addr, eskm_primarykeyserver_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " body[\"KeyManagerConfig\"] = dict()\n",
+ " body[\"KeyManagerConfig\"][\"LoginName\"] = eskm_username\n",
+ " body[\"KeyManagerConfig\"][\"Password\"] = eskm_password\n",
+ " body[\"KeyManagerConfig\"][\"AccountGroup\"] = eskm_accountgroup\n",
+ " body[\"KeyManagerConfig\"][\"ESKMLocalCACertificateName\"] = \"\"\n",
+ " body[\"PrimaryKeyServerAddress\"] = eskm_primarykeyserver_addr\n",
+ " body[\"PrimaryKeyServerPort\"] = eskm_primarykeyserver_port\n",
+ " resp = _redfishobj.patch(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3e8e7af9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ " \n",
+ "The code below establishes a connection with an iLO server using the specified system URL, login account, and password. It then sets the primary ESKM key server address and port. The script utilizes the Redfish protocol to communicate with the server and performs the necessary operations to configure the key server. Finally, it logs out from the iLO server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fac3032c",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "40aabbdc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " ESKM_USERNAME = \"admin\"\n",
+ " ESKM_PASSWORD = \"password\"\n",
+ " ESKM_ACCOUNTGROUP = \"group\"\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR = \"192.168.1.10\"\n",
+ " ESKM_PRIMARYKEYSERVER_PORT = 5927\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " ESKM_username_pass(REDFISHOBJ, ESKM_USERNAME, ESKM_PASSWORD, ESKM_ACCOUNTGROUP, \\\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR, ESKM_PRIMARYKEYSERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/set_ESKM_username_password.ipynb b/example_jupyter_notebooks/eskm/set_ESKM_username_password.ipynb
new file mode 100644
index 0000000..f38c417
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/set_ESKM_username_password.ipynb
@@ -0,0 +1,289 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Setting the ESKM username and password for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
setting the ESKM username and password for HPE iLO systems As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about ESKM_username_pass function
\n",
+ " \n",
+ "1. The function sets up an Electronic Software Key Manager (ESKM) on an iLO (Integrated Lights Out) server using the Redfish API.
\n",
+ "
\n",
+ " \n",
+ "2. It takes several input parameters including ESKM username, password, account group, primary key server address, and primary key server port.
\n",
+ "
\n",
+ "\n",
+ "3. It first attempts to locate the URI for the ESKM resource either by using the Redfish Resource Directory or by manually navigating through the Redfish API.br>\n",
+ "
\n",
+ "\n",
+ "4. If the ESKM URI is found, the function constructs a JSON payload containing the ESKM configuration information and primary key server details and sends it as a PATCH request to the ESKM resource.
\n",
+ "
\n",
+ "5. If the PATCH request is successful (i.e., returns an HTTP status code of 200), the function prints out a success message along with the response payload, otherwise it prints out an error message.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ESKM_username_pass(_redfishobj, eskm_username, eskm_password, eskm_accountgroup, \\\n",
+ " eskm_primarykeyserver_addr, eskm_primarykeyserver_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " body[\"KeyManagerConfig\"] = dict()\n",
+ " body[\"KeyManagerConfig\"][\"LoginName\"] = eskm_username\n",
+ " body[\"KeyManagerConfig\"][\"Password\"] = eskm_password\n",
+ " body[\"KeyManagerConfig\"][\"AccountGroup\"] = eskm_accountgroup\n",
+ " body[\"KeyManagerConfig\"][\"ESKMLocalCACertificateName\"] = \"\"\n",
+ " body[\"PrimaryKeyServerAddress\"] = eskm_primarykeyserver_addr\n",
+ " body[\"PrimaryKeyServerPort\"] = eskm_primarykeyserver_port\n",
+ " resp = _redfishobj.patch(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " ESKM_USERNAME = \"admin\"\n",
+ " ESKM_PASSWORD = \"password\"\n",
+ " ESKM_ACCOUNTGROUP = \"group\"\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR = \"192.168.1.10\"\n",
+ " ESKM_PRIMARYKEYSERVER_PORT = 5927\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " ESKM_username_pass(REDFISHOBJ, ESKM_USERNAME, ESKM_PASSWORD, ESKM_ACCOUNTGROUP, \\\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR, ESKM_PRIMARYKEYSERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/eskm/test_ESKM_connection.ipynb b/example_jupyter_notebooks/eskm/test_ESKM_connection.ipynb
new file mode 100644
index 0000000..780ec30
--- /dev/null
+++ b/example_jupyter_notebooks/eskm/test_ESKM_connection.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "17caee10",
+ "metadata": {},
+ "source": [
+ "Test ESKM Connection
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ca92dce",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d5c69ec2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "149adcfa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c74f9b37",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our test_ESKM_connection function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The test_ESKM_connection_ilo_firmware function takes one parameter - _redfishobj.\n",
+ "
\n",
+ " \n",
+ "2. Initialize the eskm_uri and body variables to None and an empty dictionary, respectively.\n",
+ "
\n",
+ "\n",
+ "3. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "5. Check if eskm_uri has been set. If eskm_uri is not None, retrieve the URI for the ESKM service.\n",
+ "
\n",
+ "\n",
+ "6. If the ESKM URI is available, retrieve the URI for testing the ESKM connection from the response.\n",
+ "
\n",
+ "\n",
+ "7. Set the Action field of the body dictionary to \"HpeESKM.TestESKMConnections\".\n",
+ "
\n",
+ " \n",
+ "8. Call the post() method of the _redfishobj object with the ESKM test connection URI and the body dictionary as parameters.\n",
+ "
\n",
+ " \n",
+ "9. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the JSON-formatted response.\n",
+ " \n",
+ " \n",
+ "10. If eskm_uri is None, print an error message.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "96ac0e95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def test_ESKM_connection(_redfishobj):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ "\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " eskm_test_conn_uri = _redfishobj.get(eskm_uri).obj['Actions']['#HpeESKM.TestESKMConnections']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.TestESKMConnections\"\n",
+ " resp = _redfishobj.post(eskm_test_conn_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "beb17e66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to test connection to ESKM Systems.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. Then we call test_ESKM_connection with our redfish object as parameter.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "571dd05d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09b2811e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " test_ESKM_connection(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0cdf874",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/fw_info_and_flash/flash_firmware_by_uefi.ipynb b/example_jupyter_notebooks/fw_info_and_flash/flash_firmware_by_uefi.ipynb
new file mode 100644
index 0000000..e951cf7
--- /dev/null
+++ b/example_jupyter_notebooks/fw_info_and_flash/flash_firmware_by_uefi.ipynb
@@ -0,0 +1,398 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Uploading Firmware to the iLO Repository For Flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
uploading firmware to the iLO Repository for flashings As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from random import randint\n",
+ "\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "import logging\n",
+ "from redfish import redfish_logger\n",
+ "\n",
+ "from ilorest_util import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "102138e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "LOGGERFILE = \"RedfishApiExamples.log\"\n",
+ "LOGGERFORMAT = \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n",
+ "LOGGER = redfish_logger(LOGGERFILE, LOGGERFORMAT, logging.DEBUG)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about upload_firmware function
\n",
+ " \n",
+ "1. The function upload_firmware takes in parameters such as _redfishobj, firmware_loc, comp_type, update_repo, and update_target..
\n",
+ "
\n",
+ " \n",
+ "2. It uploads firmware to a specified location using the Redfish API and HTTP POST request.
\n",
+ "
\n",
+ "\n",
+ "3. The function first obtains the UpdateService URI and HttpPushUri using the _redfishobj and then reads the firmware file as binary data.
\n",
+ "
\n",
+ "\n",
+ "4. It creates a payload containing the session key, JSON data, and the firmware file in multipart-form data format..
\n",
+ "
\n",
+ "5. Finally, the function sends the payload as an HTTP POST request to the specified path and returns an appropriate response based on the HTTP status code.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, comp_type, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " print (update_service_uri)\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ " print (path)\n",
+ "\n",
+ " body = []\n",
+ "\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " #ImageLocation = \"c:\\\\test\"\n",
+ " #filename = \"I41_2.40_08_10_2020.fwpkg\"\n",
+ " #ImagePath = os.path.join(ImageLocation, filename)\n",
+ " #file_name = os.path.basename(firmware_loc)\n",
+ " #print (ImagePath)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(file_tuple)\n",
+ " #print (body)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " print ('Begin upload....please wait...')\n",
+ " # We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2b320019",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is about create task function
\n",
+ " \n",
+ "1. The function create_task takes in parameters such as _redfishobj, firmware_loc, and tpm_flag.
\n",
+ "
\n",
+ " \n",
+ "2. It creates a new task for applying firmware updates using the Redfish API and HTTP POST request.
\n",
+ "
\n",
+ "\n",
+ "3. The function first obtains the session key and creates the necessary header dictionary for the HTTP request.It then checks if there are any current tasks in the task queue before creating a new task with a random ID and the given firmware file name.
\n",
+ "
\n",
+ "\n",
+ "4. The task is created using the update_task dictionary and sent as an HTTP POST request to the specified path.
\n",
+ "
\n",
+ "5. Finally, the function returns an appropriate response based on the HTTP status code.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09f2bc6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def create_task(_redfishobj, firmware_loc, tpm_flag=True):\n",
+ "\n",
+ " session_key = _redfishobj.session_key\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " updatable_by = ['Uefi']\n",
+ " task_path = '/redfish/v1/UpdateService/UpdateTaskQueue/'\n",
+ " file_name = os.path.basename(firmware_loc)\n",
+ "\n",
+ " task_resp = _redfishobj.get(task_path)\n",
+ " if not task_resp.obj[\"Members@odata.count\"]:\n",
+ " print (\"No current tasks, proceed to create new task\")\n",
+ "\n",
+ "\n",
+ " update_task = {'Name': 'Update-%s-%s' % (str(randint(0, 1000000)), \\\n",
+ " file_name), 'Command': 'ApplyUpdate',\\\n",
+ " 'Filename': file_name, 'UpdatableBy': updatable_by, 'TPMOverride': tpm_flag}\n",
+ "\n",
+ " resp = _redfishobj.post(task_path, update_task, headers=header)\n",
+ " #print (resp)\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to create update task queue...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Task Queue Creation complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bcac4f85",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
4.
\n",
+ "
The Main function:
PLEASE PROVIDE THE FOLLOWING CREDENTIALS HERE TO PROCEED FURTHER\n",
+ "
\n",
+ " - The path to the firmware file to upload (-c/--component)
\n",
+ " - The iLO IP of the server (-i/--ilo)
\n",
+ " - The iLO username to login (-u/--user)
\n",
+ " - The iLO password to log in (-p/--password)
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-c',\n",
+ " '--component',\n",
+ " dest='comp_path',\n",
+ " action=\"store\",\n",
+ " required=True,\n",
+ " help=\"The path to the firmware file to upload\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-s',\n",
+ " '--session_key',\n",
+ " dest='session_key',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"Http session key for the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " update_repo_flag = True\n",
+ " # Update the system with the firmware file\n",
+ " update_target_flag = False\n",
+ "\n",
+ " comp_type = 'C'\n",
+ " tpm_flag = True\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ " #system_url = \"https://\" + \"15.146.46.49\"\n",
+ " #session_id = \"515b196969f7d879886ee4a2da4ccba8\"\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " if options.session_key:\n",
+ " redfish_obj = RedfishClient(base_url=system_url, session_key= options.session_key)\n",
+ " else:\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(redfish_obj, options.comp_path, comp_type, update_repo_flag, update_target_flag)\n",
+ " if comp_type == 'C':\n",
+ " create_task(redfish_obj, options.comp_path, tpm_flag)\n",
+ "\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/fw_info_and_flash/software_firmware_inventory.ipynb b/example_jupyter_notebooks/fw_info_and_flash/software_firmware_inventory.ipynb
new file mode 100644
index 0000000..f0253db
--- /dev/null
+++ b/example_jupyter_notebooks/fw_info_and_flash/software_firmware_inventory.ipynb
@@ -0,0 +1,288 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "90595900",
+ "metadata": {},
+ "source": [
+ "Script for viewing the firmware inventory on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "887d7741",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "830d2b30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2a88487d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "827bf8e1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_inventory_uri function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function initializes the update_service_uri and inventory_uri variables to None.
\n",
+ " \n",
+ "2. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.
\n",
+ "\n",
+ "3. If the resource directory is available, find the relevant URI from the resource directory.
\n",
+ "\n",
+ "4. Check if update_service_uri has been set. If update_service_uri is not None, retrieve the URI for the update service.
\n",
+ "\n",
+ "5. Retrieve the update service response using the get() method on _redfishobj. If the provided selection contains the word \"software\" (case insensitive), set the inventory_uri to the URI of the software inventory obtained from the update service response.
\n",
+ "\n",
+ "6. If the provided selection contains the word \"firmware\" (case insensitive), set the inventory_uri to the URI of the firmware inventory obtained from the update service response.
\n",
+ " \n",
+ "7. If an invalid selection is provided, raise an exception with an error message.
\n",
+ " \n",
+ "8. Print the inventory URI.
\n",
+ " \n",
+ "9. Call the get_inventory() function, passing _redfishobj and inventory_uri as parameters.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a11214ba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory_uri(_redfishobj, select):\n",
+ "\n",
+ " update_service_uri = None\n",
+ " inventory_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if update_service_uri:\n",
+ " update_service_resp = _redfishobj.get(update_service_uri)\n",
+ " if \"software\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['SoftwareInventory']['@odata.id']\n",
+ " elif \"firmware\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['FirmwareInventory']['@odata.id']\n",
+ " else:\n",
+ " raise Exception(\"Invalid selection provided: Please select 'software' or 'firmware' to obtain the relevant invetory data.\")\n",
+ " sys.stdout.write(\"Printing data in invetory: %s\\n\" % inventory_uri)\n",
+ " get_inventory(_redfishobj, inventory_uri)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c329bc0f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is our get_inventory function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function retrieves the list of members from the provided inventory_uri using the get() method on _redfishobj.
\n",
+ " \n",
+ "2. If there are no members in the inventory, print a message indicating that the inventory is empty.
\n",
+ "\n",
+ "3. Iterate over each inventory item in the list of members.
\n",
+ "\n",
+ "4. Retrieve the details of each inventory item using the get() method on _redfishobj with the item's URI.
\n",
+ "\n",
+ "5. Print the name and description of the inventory item.
\n",
+ "\n",
+ "6. Print the JSON-formatted contents of the inventory item.
\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6ea93329",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory(_redfishobj, inventory_uri):\n",
+ "\n",
+ " _members = _redfishobj.get(inventory_uri).obj['Members']\n",
+ " if not _members:\n",
+ " sys.stderr.write(\"\\tInventory empty.\\n\")\n",
+ " else:\n",
+ " for inventory_item in _members:\n",
+ " _resp = _redfishobj.get(inventory_item['@odata.id'])\n",
+ " sys.stdout.write(\"Printing contents of inventory item, \\'%s\\':\\'%s\\'\\n\" % (_resp.dict.get('Name'), _resp.dict.get('Description')))\n",
+ " print(json.dumps(_resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3c50b324",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. SELECT variable is by default set to 'firmware'. But one can choose either 'software' or 'firmware' for inventory selection.
\n",
+ " \n",
+ "6. Then we call get_inventory_uri with our redfish object and SELECT variable.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91f1a8a5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ccf0065",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " \n",
+ " SELECT = \"firmware\" #provide either 'software' or 'firmware' for inventory selection\n",
+ " \n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_inventory_uri(REDFISHOBJ, SELECT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb99bfc3",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/fw_info_and_flash/update_iLO_firmware.ipynb b/example_jupyter_notebooks/fw_info_and_flash/update_iLO_firmware.ipynb
new file mode 100644
index 0000000..4b36168
--- /dev/null
+++ b/example_jupyter_notebooks/fw_info_and_flash/update_iLO_firmware.ipynb
@@ -0,0 +1,260 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Update Firmware via HTTP URL
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1a50e99e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3af51f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c723fbdf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b42060d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our update_ilo_firmware function overview, in the end this will update the iLO Firmware.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The update_ilo_firmware function takes three parameters - _redfishobj representing the connection to the server, fw_url representing the firmware update URL, and tpm_flag representing the TPM override flag.\n",
+ "
\n",
+ " \n",
+ "2. The function initializes the body and update_service_uri variables to None.\n",
+ "
\n",
+ "\n",
+ "3. The get_resource_directory() function is called by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, the relevant URI is found by navigating through the server's API. If the resource directory is available, the relevant URI is found from the resource directory.\n",
+ "
\n",
+ "\n",
+ "4. If update_service_uri and fw_url are not None, the update_uri is retrieved from the server using the get() method and by accessing the Actions attribute.\n",
+ "
\n",
+ "\n",
+ "5. The body dictionary is updated with the fw_url and tpm_flag if tpm_flag is provided.\n",
+ "
\n",
+ "\n",
+ "6. The post() method is called on the update_uri with the body dictionary as a parameter. The response is stored in the resp variable.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, the iLO extended info error message is printed. If the HTTP response status code is not 200 or 201, an error message is printed. If the HTTP response status code is 200 or 201, a success message is printed along.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59bfcc8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def update_ilo_firmware(_redfishobj, fw_url, tpm_flag):\n",
+ "\n",
+ " body = dict()\n",
+ " update_service_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if update_service_uri and fw_url:\n",
+ " update_uri = _redfishobj.get(update_service_uri).obj['Actions']['#UpdateService.SimpleUpdate']['target']\n",
+ " body[\"ImageURI\"] = fw_url\n",
+ " if tpm_flag:\n",
+ " body[\"TPMOverrideFlag\"] = tpm_flag\n",
+ " resp = _redfishobj.post(update_uri, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bb9670c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to update the firmware.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call update_ilo_firmware with our redfish object, FIRMWARE_URL and Trusted Platform Module (TPM) Flag as parameters.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for Firmware URL, enter the firmware file path. Example: \"http://\">
\n",
+ " \n",
+ "8. If a TPM module (Trusted Platform Module / Cryptographic Co-processor) is installed/present onboard then be sure to include this by changing TPM_FLAG variable to True. By default this variable is set to False.
\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "82f44947",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "98301396",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # firmware file path and filename\n",
+ " FIRMWARE_URL = input(\"Enter Firmware URL\")\n",
+ " \n",
+ " # If a TPM module (Trusted Platform Module/ Cryptographic Co-processor) is installed/present\n",
+ " # onboard then be sure to include this.\n",
+ " \n",
+ " TPM_FLAG = False\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " update_ilo_firmware(REDFISHOBJ, FIRMWARE_URL, TPM_FLAG)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cce9c778",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_iLO_repository_with_COMPSIG.ipynb b/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_iLO_repository_with_COMPSIG.ipynb
new file mode 100644
index 0000000..3693313
--- /dev/null
+++ b/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_iLO_repository_with_COMPSIG.ipynb
@@ -0,0 +1,287 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7fdda07e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware component and associated Component Signature (.comsig) file to iLO repository
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7574d95",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b1692ebb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0a03dc92",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ce6577f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware component along with compsig to the iLO Repository.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function takes four parameters: _redfishobj which is the Redfish client object, firmware_loc which is the path to the firmware image file, compsig_loc which is the path to the firmware image signature file, update_repo which is a boolean flag to specify whether to update the firmware repository or not, and update_target which is a boolean flag to specify whether to update the target device or not.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then the function retrieves the update service URI from the response of the previous step.\n",
+ "
\n",
+ "\n",
+ "4. The function reads the firmware and signature files and prepares the data in the required format to upload the firmware using the HttpPushUri. The function builds a list of tuples that contain the session key, json data, firmware file, and firmware signature file.\n",
+ "
\n",
+ "\n",
+ "5. The function creates a header dictionary containing the session key.\n",
+ "
\n",
+ "\n",
+ "6. The function passes the list of payload to the _redfishobj.post() method with the HttpPushUri as the path to upload the firmware and signature files.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, print an error message indicating that the firmware upload failed with the HTTP response message. If the HTTP response status code is neither 200 nor 201, print an error message indicating that an HTTP response with the status code was returned. If the HTTP response status code is 200 or 201, print a success message indicating that the firmware upload is complete.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "53612a22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, compsig_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " compsigname = os.path.basename(compsig_loc)\n",
+ " with open(compsig_loc, 'rb') as cle:\n",
+ " compsigoutput = cle.read()\n",
+ "\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ " compsig_tuple = ('compsig', (compsigname, compsigoutput, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(compsig_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware... Error: '%s'\\n\" % str(resp))\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "85b41e74",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for entering Firmware companent path, enter the entire path containing the firmware component.. Example: \"/path/to/cpxxxxxx.exe\"
The path to the firmware component file to upload. .rpm and .zip component are also valid.
\n",
+ " \n",
+ "8. When prompted for entering compsig path, enter the entire path containing the Component Signature (compsig) file having .compsig extension.. Example: \"/path/to//cpxxxxxx.compsig\"
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6ee4ac0a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17305248",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware component file to upload.\n",
+ " # .rpm and .zip component are also valid.\n",
+ " #\n",
+ " \n",
+ " FIRMWARE_PATH = input(\"Enter firmware path \")\n",
+ " COMPSIG_PATH = input(\"Enter compsig path \")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cacde035",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_to_iLO_repository.ipynb b/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_to_iLO_repository.ipynb
new file mode 100644
index 0000000..306e134
--- /dev/null
+++ b/example_jupyter_notebooks/fw_info_and_flash/upload_firmware_to_iLO_repository.ipynb
@@ -0,0 +1,276 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware to iLO repository for flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1ab478ee",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "183ac248",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7bede674",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b72b845",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware to the iLO Repository for flashing.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload the firmware.
\n",
+ "\n",
+ "1. The function takes these parameters as input: _redfishobj, firmware_loc, update_repo, and update_target.\n",
+ "
\n",
+ " \n",
+ "2. It calls the get_resource_directory() function by passing the _redfishobj parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, it obtains all account instances from the resource directory and then retrieves the URI for the Update Service.\n",
+ "
\n",
+ "\n",
+ "4. The function then sends an HTTP GET request to the obtained URI to retrieve the HttpPushUri path.\n",
+ "
\n",
+ "\n",
+ "5. It then reads the firmware file using the open() method and stores its contents in the output variable.\n",
+ "
\n",
+ "\n",
+ "6. The function builds the payload for the multipart-form data using session key, parameters, and firmware file tuples.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. It then creates a header dictionary containing the session key and passes the whole payload to the post() method.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "8. If the HTTP response status code is not 200 or 201, it prints an error message. If the HTTP response status code is 400, it prints a \"Failed to upload firmware...\" error message. If the HTTP response status code is 200 or 201, it prints a success message.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "beb01150",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4041fb30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted, enter the entire path containing the new firmware (.fwpkg). Example: \"C:\\\\Users\\\\oconnogr\\\\git\\\\python-restful-interface-tool\\\\src\\\\ilo5_230_p31.fwpkg\"\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dbfb1f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d3ff3bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware file to upload\n",
+ " FIRMWARE_PATH = input(\"Enter entire path containing the Firmware (.fwpkg)\")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6d44e9b",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/get_resource_directory.py b/example_jupyter_notebooks/get_resource_directory.py
new file mode 100644
index 0000000..0b231cf
--- /dev/null
+++ b/example_jupyter_notebooks/get_resource_directory.py
@@ -0,0 +1,64 @@
+ # Copyright 2020 Hewlett Packard Enterprise Development LP
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
+ # not use this file except in compliance with the License. You may obtain
+ # a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ # License for the specific language governing permissions and limitations
+ # under the License.
+
+# -*- coding: utf-8 -*-
+"""
+An example of getting the ilo information like ilo generation, version and resource directory for HPE iLO systems
+"""
+
+import sys
+from redfish import RedfishClient
+from redfish.rest.v1 import ServerDownOrUnreachableError
+
+def get_resource_directory(redfishobj):
+
+ try:
+ resource_uri = redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id']
+ except KeyError:
+ sys.stderr.write("Resource directory is only available on HPE servers.\n")
+ return None
+
+ response = redfishobj.get(resource_uri)
+ resources = []
+
+ if response.status == 200:
+ sys.stdout.write("\tFound resource directory at /redfish/v1/resourcedirectory" + "\n\n")
+ resources = response.dict["Instances"]
+ else:
+ sys.stderr.write("\tResource directory missing at /redfish/v1/resourcedirectory" + "\n")
+
+ return resources
+
+def get_gen(_redfishobj):
+ rootresp = _redfishobj.root.obj
+ #Default iLO 5
+ ilogen = 5
+ gencompany = next(iter(rootresp.get("Oem", {}).keys()), None) in ('Hpe', 'Hp')
+ comp = 'Hp' if gencompany else None
+ comp = 'Hpe' if rootresp.get("Oem", {}).get('Hpe', None) else comp
+ if comp and next(iter(rootresp.get("Oem", {}).get(comp, {}).get("Manager", {}))).\
+ get('ManagerType', None):
+ ilogen = next(iter(rootresp.get("Oem", {}).get(comp, {}).get("Manager", {})))\
+ .get("ManagerType")
+ ilover = next(iter(rootresp.get("Oem", {}).get(comp, {}).get("Manager", {}))).\
+ get("ManagerFirmwareVersion")
+ if ilogen.split(' ')[-1] == "CM":
+ # Assume iLO 4 types in Moonshot
+ ilogen = 4
+ iloversion = None
+ else:
+ ilogen = ilogen.split(' ')[1]
+ iloversion = float(ilogen.split(' ')[-1] + '.' + \
+ ''.join(ilover.split('.')))
+ return (ilogen, iloversion)
diff --git a/example_jupyter_notebooks/ilo_license/get_license_key.ipynb b/example_jupyter_notebooks/ilo_license/get_license_key.ipynb
new file mode 100644
index 0000000..4f33710
--- /dev/null
+++ b/example_jupyter_notebooks/ilo_license/get_license_key.ipynb
@@ -0,0 +1,226 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fd1f8e82",
+ "metadata": {},
+ "source": [
+ "Retrieving iLO License Key for HPE iLO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c2413866",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d3890182",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2f0e994d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "46f46a25",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. The purpose of the get_license_key function is to retrieve the license key information for HPE iLO (Integrated Lights-Out) systems using the Redfish API.
\n",
+ " Here's a step-by-step breakdown of what the function does:\n",
+ "
\n",
+ "- Initialization: The function initializes variables license_uri and license_data to store the license key URI and data, respectively.\n",
+ "
- Resource Directory Check: It checks if the resource directory is disabled or not available. If so, it follows a specific set of steps to locate the license key URI.\n",
+ "
- License Key Retrieval: If the resource directory is not used, the function retrieves the license key URI and data by making appropriate API requests to the HPE server.\n",
+ "
- Resource Directory Usage: If the resource directory is available, the function utilizes it to find the relevant URI for the license key.\n",
+ "
- Output: If the license data is obtained successfully, the function prints the license information, including the confirmation request or the license key itself, depending on the available data.\n",
+ "
Overall, the get_license_key function encapsulates the logic to obtain the license key for HPE iLO systems, considering different scenarios such as the presence or absence of the resource directory.\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9aa55d07",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_license_key(_redfishobj):\n",
+ " license_uri = None\n",
+ " license_data = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " hp_hpe = next(iter(managers_members_response.obj.Oem))\n",
+ " license_collection_uri = managers_members_response.obj.Oem[hp_hpe].Links['LicenseService']\\\n",
+ " ['@odata.id']\n",
+ " license_collection_response = _redfishobj.get(license_collection_uri)\n",
+ " license_collection_members_uri = next(iter(license_collection_response.obj\\\n",
+ " ['Members']))['@odata.id']\n",
+ " license_data = _redfishobj.get(license_collection_members_uri).dict\n",
+ " license_uri = _redfishobj.get(license_collection_members_uri).dict['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOLicense.' in instance['@odata.type']:\n",
+ " license_uri = instance['@odata.id']\n",
+ " license_data = _redfishobj.get(license_uri).dict\n",
+ " break\n",
+ "\n",
+ " if license_data:\n",
+ " try:\n",
+ " sys.stdout.write(\"\\n\\'License Info\\': \\'%s\\'\\n\" % \\\n",
+ " json.dumps(license_data['ConfirmationRequest']['EON'], indent=4, sort_keys=True))\n",
+ " except KeyError:\n",
+ " sys.stdout.write(\"\\n\\'License Info\\': \\'%s\\'\\n\" % \\\n",
+ " json.dumps(license_data['LicenseKey'], indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91d5455c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is the Main function overview.
\n",
+ "
\n",
+ "
- Sets up the configuration parameters for the HPE iLO system, including the system URL, login account, and password.\n",
+ "
- Attempts to create a Redfish client object using the specified configuration parameters to establish a connection with the iLO system.\n",
+ "
- If the connection is successful, the script proceeds to execute the get_license_key function to retrieve the iLO license key.\n",
+ "
- After retrieving the license key, the script logs out from the Redfish client by calling the logout function to end the session and release resources.\n",
+ "
- If the connection to the iLO system fails or the server is unreachable, an error message is displayed, and the script exits.\n",
+ "
In summary, the main function establishes a connection with the HPE server, retrieves ESKM data, and ensures a clean logout from the server.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac6a6e08",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally, use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3f42625",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_license_key(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ilo_license/set_license_key.ipynb b/example_jupyter_notebooks/ilo_license/set_license_key.ipynb
new file mode 100644
index 0000000..b6e3b33
--- /dev/null
+++ b/example_jupyter_notebooks/ilo_license/set_license_key.ipynb
@@ -0,0 +1,253 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7d91ced6",
+ "metadata": {},
+ "source": [
+ "Setting license key
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "11b0fe9d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting license key. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6cbd5f7c",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f0fa1574",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7daccb24",
+ "metadata": {},
+ "source": [
+ "2. This is our set_license_key function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
set_license_key function we are taking two parameters i.e.
_redfishobj and
ilo_key. In the
set_license_key function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about license key is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the license service about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The license service information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeiLOLicense type is present in
@odata.type attribute then we will store information about license key in ilo_lic_uri and break out of iteration.\n",
+ "
\n",
+ "5.
If ilo_lic_uri is not null after making above operations, we can perform the required actions to set license key. \n",
+ "
\n",
+ " - The function sends a GET request to the iLO license service to retrieve the current license data. If the ConfirmationRequest field exists, it is printed to the console; otherwise, the LicenseKey field is printed.
\n",
+ "- The function sends a POST request to the iLO license service with the new license key provided in the ilo_key argument.
\n",
+ " - The job of post request here is to set the license key at the provided location and send a response whether the job was done properly or not.
\n",
+ " - If the response status is 400, the function attempts to print the extended error message provided by iLO. If the status is not 200 or 201, the function prints an error message to the console.
\n",
+ "- If the response status is 200, the function prints a success message to the console along with the response JSON.
\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bacca62e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_license_key(_redfishobj, ilo_key):\n",
+ "\n",
+ " ilo_lic_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " ilo_lic_uri = managers_members_response.obj.Oem.Hpe.Links['LicenseService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOLicense.' in instance['@odata.type']:\n",
+ " ilo_lic_uri = instance['@odata.id']\n",
+ "\n",
+ " if ilo_lic_uri:\n",
+ " ilo_license_collection = _redfishobj.get(ilo_lic_uri)\n",
+ " ilo_license_member_uri = next(iter(ilo_license_collection.obj['Members']))['@odata.id']\n",
+ " try:\n",
+ " ilo_license_data = _redfishobj.get(ilo_license_member_uri).obj['ConfirmationRequest']\\\n",
+ " ['EON']\n",
+ " except KeyError:\n",
+ " sys.stdout.write(\"This machine will not show the full License Key.\\n\")\n",
+ " ilo_license_data = _redfishobj.get(ilo_license_member_uri).obj['LicenseKey']\n",
+ "\n",
+ " sys.stdout.write(\"Current iLO License Data:\\n\")\n",
+ " print(json.dumps(ilo_license_data, indent=4, sort_keys=True))\n",
+ " resp = _redfishobj.post(ilo_lic_uri, {'LicenseKey' : ilo_key})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stderr.write(\"Check the validity of your license key...\\n\")\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \" \\\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "abfa5bd8",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to set_license_key function to set license key of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7d4c55f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38798e69",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Must be a valid iLO License Key\n",
+ " ILO_LICENSE_KEY = \"XXXX-XXXX-XXXX-XXXX-XXXXX\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_license_key(REDFISHOBJ, ILO_LICENSE_KEY)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3be89a3",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/index.ipynb b/example_jupyter_notebooks/index.ipynb
new file mode 100644
index 0000000..6715b7a
--- /dev/null
+++ b/example_jupyter_notebooks/index.ipynb
@@ -0,0 +1,1014 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9465e40",
+ "metadata": {},
+ "source": [
+ "INDEX
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "Scripts related to BIOS
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7eaa85e8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change BIOS Settings | \n",
+ " Update BIOS Settings for iLO server | \n",
+ " PATCH | \n",
+ " BIOS_changeSettings | \n",
+ "
\n",
+ " \n",
+ " | BIOS Default | \n",
+ " Update BIOS to default setting | \n",
+ " POST | \n",
+ " BIOS_revertToDefault | \n",
+ "
\n",
+ " \n",
+ " | Set bios password | \n",
+ " Change bios password for HPE iLO system | \n",
+ " PATCH | \n",
+ " set_bios_password | \n",
+ "
\n",
+ " \n",
+ " | Set bios ISCSI | \n",
+ " Setting an ISCSI boot instance for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_bios_iscsi | \n",
+ "
\n",
+ " \n",
+ " | Get base registry | \n",
+ " Gathering base registry Data for HPE iLO Systems | \n",
+ " GET | \n",
+ " get_base_registry | \n",
+ "
\n",
+ " \n",
+ " | Get BIOS Settings | \n",
+ " Retrieving bios settings from iLO servers | \n",
+ " GET | \n",
+ " get_bios_settings | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b01ddc4e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "Scripts related to Users and Sessions
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1f075a76",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Add User Account | \n",
+ " Add new user account | \n",
+ " POST | \n",
+ " add_user_account | \n",
+ "
\n",
+ " \n",
+ " | Manually Managing Sessions With Redfish | \n",
+ " creates a new session with an iLO server | \n",
+ " POST | \n",
+ " sessions | \n",
+ "
\n",
+ " \n",
+ " | Delete User Account | \n",
+ " delete user account | \n",
+ " DELETE | \n",
+ " delete_user_account | \n",
+ "
\n",
+ " \n",
+ " | Modify User Account | \n",
+ " Modify an iLO user account on the server | \n",
+ " GET,PATCH | \n",
+ " modify_user_account | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9f91683a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e16cdec",
+ "metadata": {},
+ "source": [
+ "Scripts related to Booting
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616fef86",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change Boot Order | \n",
+ " Change iLOs boot ordert | \n",
+ " PATCH | \n",
+ " change_boot_order | \n",
+ "
\n",
+ " \n",
+ " | Change Temporary Boot Order | \n",
+ " Change iLOs temporary boot ordert | \n",
+ " PATCH | \n",
+ " change_temp_boot_order | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "317bbec4",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "387dc1d0",
+ "metadata": {},
+ "source": [
+ "Scripts related to Enterprise Secure Key Manager (ESKM)
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5f1b24c1",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Test ESKM Connection | \n",
+ " Script for testing connection to the ESKM system for HPE iLO systems | \n",
+ " POST | \n",
+ " test_ESKM_connection | \n",
+ "
\n",
+ " \n",
+ " | Gathering ESKM Data | \n",
+ " Collecting ESKM (Enterprise Secure Key Manager) data for HPE iLO | \n",
+ " GET | \n",
+ " get_ESKM | \n",
+ "
\n",
+ " \n",
+ " | Set ESKM Primary Key | \n",
+ " Configure the ESKM key server for HPE iLO systems | \n",
+ " POST | \n",
+ " set_ESKM_PrimaryKeyServer | \n",
+ "
\n",
+ " \n",
+ " | Set ESKM Username and Password | \n",
+ " Set the ESKM (Enterprise Secure Key Manager) username, password, and other configurations for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_ESKM_username_pass | \n",
+ "
\n",
+ " \n",
+ " | reset ESKM eventlog | \n",
+ " reset the ESKM (Enterprise Secure Key Manager) event log using the iLO API | \n",
+ " POST | \n",
+ " ESKM_eventlog | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c53f260c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acef9e30",
+ "metadata": {},
+ "source": [
+ "Scripts related to Firmware and Flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bfe4eeac",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Upload Firmware to iLO repository | \n",
+ " Script for uploading firmware to the iLO Repository for flashing | \n",
+ " POST | \n",
+ " upload_firmware_to_iLO_repo | \n",
+ "
\n",
+ " \n",
+ " | Upload Firmware with associated COMPSIG file to iLO repository | \n",
+ " Script for uploading a firmware component with a size less than\n",
+ "32 GB, and associated Component Signature (compsig) signature file to the iLO Repository | \n",
+ " POST | \n",
+ " Upload_fw_iLO_Repo_COMPSIG | \n",
+ "
\n",
+ " \n",
+ " | Update Firmware | \n",
+ " Script for updating Firmware via HTTP URL | \n",
+ " POST | \n",
+ " update_iLO_firmware | \n",
+ "
\n",
+ " \n",
+ " | View Firmware Inventory | \n",
+ " Script for viewing the firmware inventory on HPE iLO systems | \n",
+ " GET | \n",
+ " software_firmware_inventory | \n",
+ "
\n",
+ " \n",
+ " | Uploading Firmware to the iLO Repository For Flashing | \n",
+ " uploads firmware to a specified location using the Redfish API and HTTP POST request | \n",
+ " GET | \n",
+ " software_firmware_inventory | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7f3245b7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "774d4dc2",
+ "metadata": {},
+ "source": [
+ "Scripts related to iLO License
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6d7cc2f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set License Key\t | \n",
+ " Setting License Key | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Get License Key | \n",
+ " Retrieve iLO License Key for HPE iLO Systems | \n",
+ " GET | \n",
+ " get_license_key | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "87a754d8",
+ "metadata": {},
+ "source": [
+ "Scripts related to reset iLO
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b37a713",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | reset ilo | \n",
+ " reset the ilo using the iLO API | \n",
+ " POST | \n",
+ " reset_ilo | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d4473c5",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "473638bc",
+ "metadata": {},
+ "source": [
+ "Scripts related to Virtual Media
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39e6d1c2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Mount Virtual Media Iso\t | \n",
+ " obtain the virtual media information. | \n",
+ " PATCH | \n",
+ " mount_virtual_media_iso | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0299c78c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f1fc753",
+ "metadata": {},
+ "source": [
+ "Scripts related to SNMP
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ff18cb9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Configure SNMP | \n",
+ " Configuring SNMP for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp | \n",
+ "
\n",
+ " \n",
+ " | Configure SNMP trap source | \n",
+ " Configuring SNMP trap source for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp_trap_source | \n",
+ "
\n",
+ " \n",
+ " | Set SNMP alert destination | \n",
+ " Setting SNMP alert destination for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_snmp_alert | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a184d9af",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e43c3e0c",
+ "metadata": {},
+ "source": [
+ "Scripts related to Smart Array Storage
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "519adbf2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Smart Array Encryption Settings On HPE ILO Systems\t | \n",
+ " retrieves encryption settings for Smart Storage Array Controllers from a Redfish service. | \n",
+ " PATCH | \n",
+ " SmartArray_Encryption | \n",
+ "
\n",
+ " \n",
+ " | Logic drive | \n",
+ " Retrieves information about the smart array logical drive | \n",
+ " GET | \n",
+ " get_logical_drive | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "33d2d8b7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77acbc7f",
+ "metadata": {},
+ "source": [
+ "Scripts related to Managing Server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7dd28f1e",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Computer Details | \n",
+ " Get all the available computer/hosts details in iLO\t | \n",
+ " GET | \n",
+ " computer_details | \n",
+ "
\n",
+ " \n",
+ " | Set Server Asset Tag | \n",
+ " Setting server asset tag\t | \n",
+ " PATCH | \n",
+ " set_server_asset_tag | \n",
+ "
\n",
+ " \n",
+ " | Set UID Light | \n",
+ " Setting UID Light | \n",
+ " PATCH | \n",
+ " set_uid_light | \n",
+ "
\n",
+ " \n",
+ " | reset the server | \n",
+ " reset the server using the ilo API | \n",
+ " GET,POST | \n",
+ " reset_server | \n",
+ "
\n",
+ " \n",
+ " | Reboot the server | \n",
+ " reboot the server using the iLO API | \n",
+ " GET,POST | \n",
+ " reboot_server | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0528100d",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "60ecf170",
+ "metadata": {},
+ "source": [
+ "Scripts related to Security Certificate
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "df148ae0",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Enable_Secure_Boot\t | \n",
+ " obtain the secure boot information | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Generating a certificate signing request for HPE iLO systems¶ | \n",
+ " using resource_instances variable to obtain information about the resource directory by using get_resource_directory module. | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ " | Issusing the certificate | \n",
+ " import an SSL certificate to the iLO | \n",
+ " Post | \n",
+ " import_ssl | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a961c65",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6e78323",
+ "metadata": {},
+ "source": [
+ "Scripts related to NTP and Timezone
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf265e66",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set iLO NTP Server | \n",
+ " Setting NTP Servers for HPE iLO Systems | \n",
+ " PATCH | \n",
+ " set_ilo_ntp_servers | \n",
+ "
\n",
+ " \n",
+ " | Set iLO Timezone | \n",
+ " Setting the timezone for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_ilo_ntp_timezone | \n",
+ "
\n",
+ " \n",
+ " | Enable Ntp Servers | \n",
+ " enable NTP servers for HPE ilo systems | \n",
+ " PATCH | \n",
+ " enabling_ntp_server | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d3afe833",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "57663508",
+ "metadata": {},
+ "source": [
+ "Scripts related to Network and NIC
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb76ce7b",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get iLO IP | \n",
+ " Retrieve the IP address of an HPE iLO server | \n",
+ " GET | \n",
+ " get_ilo_ip | \n",
+ "
\n",
+ " \n",
+ " | Get iLO nic | \n",
+ " Retrieve the network interface card (NIC) configuration of the iLO server. | \n",
+ " PATCH | \n",
+ " get_ilo_nic | \n",
+ "
\n",
+ " \n",
+ " | Set Ethernet Management | \n",
+ " Set the static IP configuration for the Manager ethernet interface of an HPE iLO system | \n",
+ " GET | \n",
+ " set_ethernet_management | \n",
+ "
\n",
+ " \n",
+ " | Find ilo Mac Address | \n",
+ " finding ilo mac address related information | \n",
+ " GET | \n",
+ " find_ilo_mac_address | \n",
+ "
\n",
+ " \n",
+ " | Setting the active Manager NIC | \n",
+ " used to enable/disable Ethernet interfaces on an iLO | \n",
+ " GET | \n",
+ " get_license_key | \n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7cea8664",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "456e00fb",
+ "metadata": {},
+ "source": [
+ "Scripts related to AHS, Syslog and IML
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c073eebe",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Clear AHS data | \n",
+ " Clear active health state data of iLO server | \n",
+ " DELETE | \n",
+ " clear_ahs_data | \n",
+ "
\n",
+ " \n",
+ " | Set remote syslog server\t | \n",
+ " Setting Remote syslog Server for an HPE iLO management processor. | \n",
+ " PATCH | \n",
+ " set_syslogserver | \n",
+ "
\n",
+ " \n",
+ " | Clear iLO IEL IML log\t | \n",
+ " Clearing out the iLO event log and management log at server side | \n",
+ " DELETE | \n",
+ " clear_ilo_iel_iml_log | \n",
+ "
\n",
+ " \n",
+ " | Get AHS Data | \n",
+ " Collecting Active Health System data of iLO systems. | \n",
+ " GET | \n",
+ " get_ahs_data | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "594b46a2",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7d88adab",
+ "metadata": {},
+ "source": [
+ "Scripts related to Redfish operation and utility
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71299947",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Quickstart Redfish | \n",
+ " Interact with iLO using REDFISH for system information | \n",
+ " GET | \n",
+ " quickstart_redfish | \n",
+ "
\n",
+ " \n",
+ " | ilorest_util | \n",
+ " Retrieves the resource directory from the server and Determines the generation and version of the iLO | \n",
+ " GET | \n",
+ " ilorest_util | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9dec363f",
+ "metadata": {},
+ "source": [
+ "Scripts related to Power
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b5fa53d4",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get Power Metrics Average | \n",
+ " Script for gathering the power metrics average on HPE iLO systems | \n",
+ " GET | \n",
+ " get_powermetrics_average | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d49853c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b445d67",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ecd072de",
+ "metadata": {},
+ "source": [
+ "Miscellaneous Scripts
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "87b872fd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Example Data Resopnses | \n",
+ " Example Script for expanding data responses | \n",
+ " GET | \n",
+ " expand_data | \n",
+ "
\n",
+ " \n",
+ " | System Schema Data | \n",
+ " retrieves the URI for the root JSON schema from the Redfish service object ( | \n",
+ " GET | \n",
+ " get_schema.ipynb | \n",
+ "
\n",
+ " \n",
+ " | Resource directory | \n",
+ " Retrieves the resource directory from an HPE server and also determines the generation and version of an iLO system | \n",
+ " GET | \n",
+ " resource_directory | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "da54fe5d",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/miscellaneous/expand_data.ipynb b/example_jupyter_notebooks/miscellaneous/expand_data.ipynb
new file mode 100644
index 0000000..d0fd0df
--- /dev/null
+++ b/example_jupyter_notebooks/miscellaneous/expand_data.ipynb
@@ -0,0 +1,216 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b6480262",
+ "metadata": {},
+ "source": [
+ "Example of expanding data responses
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "051ce734",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58eab40d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cfa6671a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5f4583b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our expand_data function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The expand_data function takes two parameters: _redfishobj and expand_url, with a default value of \"/redfish/v1/\" for expand_url.
\n",
+ " \n",
+ "2. It sends a GET request to the _redfishobj (Redfish object) using the provided expand_url to retrieve the response.
\n",
+ "\n",
+ "3. Another GET request is sent to the _redfishobj with the expand_url appended with ?$expand=.. This request is used to retrieve an expanded response.
\n",
+ "\n",
+ "4. The function then prints the standard response to the standard output stream.
\n",
+ "\n",
+ "5. The standard response, represented as a dictionary, is printed.
\n",
+ "\n",
+ "6. Next, the function prints the expanded response to the standard output stream.
\n",
+ " \n",
+ "7. The expanded response, represented as a dictionary, is printed.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "509e8725",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def expand_data(_redfishobj, expand_url=\"/redfish/v1/\"):\n",
+ "\n",
+ " response = _redfishobj.get(expand_url)\n",
+ " exp_response = _redfishobj.get(expand_url+'?$expand=.')\n",
+ " sys.stdout.write('Standard response:\\n')\n",
+ " sys.stdout.write('\\t'+str(response.dict)+'\\n')\n",
+ " sys.stdout.write('Expanded response:\\n')\n",
+ " sys.stdout.write('\\t'+str(exp_response.dict)+'\\n')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "523f5bda",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. When prompted for URL, enter the URL that you want to be expanded. Example: /redfish/v1/systems/
\n",
+ " \n",
+ "6. Then we call expand_data with our redfish object and EXPAND_URL.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b80bdfed",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "eabae678",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #url to be expanded\n",
+ " EXPAND_URL = input(\"Enter the URL that is to be expanded (Ex: /redfish/v1/systems/)\")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " expand_data(REDFISHOBJ, EXPAND_URL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76b99be7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/miscellaneous/get_resource_directory.ipynb b/example_jupyter_notebooks/miscellaneous/get_resource_directory.ipynb
new file mode 100644
index 0000000..73f4d88
--- /dev/null
+++ b/example_jupyter_notebooks/miscellaneous/get_resource_directory.ipynb
@@ -0,0 +1,234 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Get_Resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_resource_directory As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " A redfishobj parameter is required for the function get_resource_directory. The resource directory can be retrieved using this function from a Redfish API.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. It tries to use the redfishobj object to access the resource directory URI. The server's resources are gathered in the resource directory.The server is not an HPE server and an error message is displayed to stderr if the resource directory URI cannot be discovered (KeyError is thrown). Then, the function returns null.\n",
+ "
\n",
+ " \n",
+ "2. If the resource directory URI is located, the code uses the redfishobj.get method to send an HTTP GET request to retrieve the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. A response status of 200 (OK) indicates a successful retrieval of the resource directory. The function assigns the list of resource instances to the resources variable and sends a message to stdout showing the location of the resource directory.\n",
+ "
\n",
+ "\n",
+ "4. If the response status isn't 200, the resource directory is either unavailable or missing. The resources variable is empty and an error is reported to stderr.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally the function get_resource_directory return the resources.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_resource_directory(redfishobj):\n",
+ "\n",
+ " try:\n",
+ " resource_uri = redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id']\n",
+ " except KeyError:\n",
+ " sys.stderr.write(\"Resource directory is only available on HPE servers.\\n\")\n",
+ " return None\n",
+ "\n",
+ " response = redfishobj.get(resource_uri)\n",
+ " resources = []\n",
+ "\n",
+ " if response.status == 200:\n",
+ " sys.stdout.write(\"\\tFound resource directory at /redfish/v1/resourcedirectory\" + \"\\n\\n\")\n",
+ " resources = response.dict[\"Instances\"]\n",
+ " else:\n",
+ " sys.stderr.write(\"\\tResource directory missing at /redfish/v1/resourcedirectory\" + \"\\n\")\n",
+ "\n",
+ " return resources\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is get_gen function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "\n",
+ "\n",
+ "1. The _redfishobj object, which is presumed to be a Redfish response object, is used to retrieve the root response.\n",
+ "The server generation's default setting is set to 5 (iLO 5).
\n",
+ "
\n",
+ " \n",
+ "2. By looking at the keys beneath the \"Oem\" key in the root response, it determines whether the OEM (Original Equipment Manufacturer) of the server is either \"Hpe\" or \"Hp.\" Gencompany is set to True if one of these keys is discovered; otherwise, it is set to False..
\n",
+ "
\n",
+ "\n",
+ "3. If gencompany is True, the variable comp is changed to Hp otherwise, it stays None.\n",
+ "Comp is changed to Hpe if comp is not None and the Oem key contains the subkey Hpe in the root response.
\n",
+ "
\n",
+ "\n",
+ "4. The function then accesses nested dictionaries in the root response to see if the server's manager type is present.It fetches the manager type and firmware version if the manager type is present.\n",
+ "It thinks the server is an iLO 4 type on a Moonshot system if the manager type ends with CM (probably \"Chassis Manager\") in which case it sets ilogen to 4 and iloversion to None.
\n",
+ "
\n",
+ "5. In the absence of that, it takes the management type's generation number and the firmware version number. These values are combined to create a decimal version number, which is then assigned to iloversion. Ilogen is given the extracted generation number.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "6. A tuple including the server generation (ilogen) and version (iloversion) is the function's final output.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_gen(_redfishobj):\n",
+ "\trootresp = _redfishobj.root.obj\n",
+ "\t#Default iLO 5\n",
+ "\tilogen = 5\n",
+ "\tgencompany = next(iter(rootresp.get(\"Oem\", {}).keys()), None) in ('Hpe', 'Hp')\n",
+ "\tcomp = 'Hp' if gencompany else None\n",
+ "\tcomp = 'Hpe' if rootresp.get(\"Oem\", {}).get('Hpe', None) else comp\n",
+ "\tif comp and next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tget('ManagerType', None):\n",
+ "\t\tilogen = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {})))\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.get(\"ManagerType\")\n",
+ "\t\tilover = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t get(\"ManagerFirmwareVersion\")\n",
+ "\t\tif ilogen.split(' ')[-1] == \"CM\":\n",
+ "\t\t\t# Assume iLO 4 types in Moonshot\n",
+ "\t\t\tilogen = 4\n",
+ "\t\t\tiloversion = None\n",
+ "\t\telse:\n",
+ "\t\t\tilogen = ilogen.split(' ')[1]\n",
+ "\t\t\tiloversion = float(ilogen.split(' ')[-1] + '.' + \\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t''.join(ilover.split('.')))\n",
+ "\treturn (ilogen, iloversion)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/miscellaneous/get_schema.ipynb b/example_jupyter_notebooks/miscellaneous/get_schema.ipynb
new file mode 100644
index 0000000..fa974d7
--- /dev/null
+++ b/example_jupyter_notebooks/miscellaneous/get_schema.ipynb
@@ -0,0 +1,212 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "15565395",
+ "metadata": {},
+ "source": [
+ "System Schema Data
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd7d6791",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4ca0edc7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1805d6fa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "404a5487",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about obtaining system schema data
\n",
+ " \n",
+ "1. The function takes a parameter, _redfishobj, which represents the Redfish service object used to interact with the API.
\n",
+ "
\n",
+ " \n",
+ "2.It initializes two variables: schema_members_uris and schema_members_expanded. schema_members_uris is an empty list that will store the URIs of schema members, while schema_members_expanded is an empty dictionary that will hold the expanded schema information.
\n",
+ "
\n",
+ "\n",
+ "3. It retrieves the URI for the root JSON schema from the Redfish service object (_redfishobj) and makes a GET request to obtain the schema response. The response contains a list of member URIs that point to individual schemas.
\n",
+ "
\n",
+ "\n",
+ "4. The function iterates through each member URI, retrieves the schema data, and expands the URI link for sub-schemas with the actual schema information. The expanded schema data is stored in the schema_members_expanded dictionary using the member URI as the key.
\n",
+ "
\n",
+ "5. The function iterates through each member URI, retrieves the schema data, and expands the URI link for sub-schemas with the actual schema information. The expanded schema data is stored in the schema_members_expanded dictionary using the member URI as the key.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "780095b1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_schema(_redfishobj):\n",
+ " schema_members_uris = []\n",
+ " schema_members_expanded = {}\n",
+ "\n",
+ " schema_uri = _redfishobj.root.obj['JsonSchemas']['@odata.id']\n",
+ " schema_response = _redfishobj.get(schema_uri)\n",
+ " schema_members_uris = schema_response.obj['Members']\n",
+ " for member in schema_members_uris:\n",
+ " data = _redfishobj.get(member['@odata.id']).dict\n",
+ " instance_id = data['Location'].index(next(iter(data['Location'])))\n",
+ " schema_uri = data['Location'][instance_id]['Uri']\n",
+ " schema = _redfishobj.get(schema_uri).dict\n",
+ " #I am just replacing the URI link for the sub-schema with the actual schema. You will\n",
+ " #see EVERYTHING\n",
+ " _tmp = {schema_uri + ' ->': schema}\n",
+ " data['Location'][instance_id]['Uri'] = _tmp\n",
+ " schema_members_expanded[member['@odata.id']] = data\n",
+ "\n",
+ " print(json.dumps(schema_members_expanded, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "071606d1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "275fe668",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a1f63d79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_schema(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d740355",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/nic_network/find_ilo_mac_address.ipynb b/example_jupyter_notebooks/nic_network/find_ilo_mac_address.ipynb
new file mode 100644
index 0000000..cfd4a78
--- /dev/null
+++ b/example_jupyter_notebooks/nic_network/find_ilo_mac_address.ipynb
@@ -0,0 +1,228 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Finding iLo Mac address"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
find_ilo_mac_address!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This is our find_ilo_mac_address function overview, in the end this will give us about finding ilo mac address related information.
\n",
+ "
Let me give you a walk through of it!
\n",
+ "
\n",
+ " - For the identification of a device, its mac address is very much required. If you have the Systems Management Homepage installed, you can find out by clicking \"Management Processor\" and then check the Physical Address field.
\n",
+ " - If we don't have a resource directory, information about the ethernet data is stored inside the managers json object. Through managers_response variable we are making a http GET operation to and trying to obtain the virtual media about iLO system.
\n",
+ " - Ethernet interface gives the response for that member about the ilo mac address
\n",
+ " - If the resource directory is present, then we will simply iterate through all instances inside resources and if the ethernet interface is present in @odata.type attribute then we will store information about ethernet interface in ethernet_data dictionary and break out of iteration.
\n",
+ " - Finally, we get iLo Network Manager Interface and iLO Mac Address as output.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_ilo_mac_address(_redfishobj):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " for iface in ethernet_data:\n",
+ " sys.stdout.write(\"iLO Network Manager Interface: \\'%s\\'\\n\" % ethernet_data[iface]['Id'])\n",
+ " sys.stdout.write(\"\\tiLO Mac Address: \\'%s\\'\\n\" % ethernet_data[iface].get('MACAddress'))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get \"server not reachable\" message!
\n",
+ " - and Once everything is done you are automatically logged out with .logout() 😁.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " find_ilo_mac_address(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/nic_network/get_ilo_ip.ipynb b/example_jupyter_notebooks/nic_network/get_ilo_ip.ipynb
new file mode 100644
index 0000000..decdc50
--- /dev/null
+++ b/example_jupyter_notebooks/nic_network/get_ilo_ip.ipynb
@@ -0,0 +1,191 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ded55c6b",
+ "metadata": {},
+ "source": [
+ "Retrieving the IP address of an HPE iLO server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "331abcaf",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8fd7760b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8fa0fe24",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
2. Below is the get_ilo_ip function.
\n",
+ "The get_ilo_ip function retrieves the IP address of an HPE iLO (Integrated Lights-Out) server.
Here's a breakdown of its functionality:
\n",
+ "\n",
+ "The function starts by obtaining the resource directory from the provided restobj, which represents the REST object.
\n",
+ "It then iterates over the resource instances in the directory to find the manager path that corresponds to the iLO server.
\n",
+ "Once the manager path is obtained, a GET request is made to retrieve the manager information.\n",
+ "The function then retrieves the Ethernet NIC information by following the link provided in the manager response.
\n",
+ "It iterates over the Ethernet NIC items and checks if the IPv4 address is not \"0.0.0.0\". If a valid IPv4 address is found, it is written to the standard output.
\n",
+ "In summary, the get_ilo_ip function utilizes the HPE iLO REST API to locate and retrieve the IP address of an iLO server. It provides a convenient way to programmatically obtain the server's network information.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ilo_ip(restobj):\n",
+ " resource_instances = get_resource_directory(restobj)\n",
+ " if resource_instances:\n",
+ " #Get URI from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if \"Manager.\" in instance.Type:\n",
+ " manager_path = instance.href\n",
+ " break\n",
+ "\n",
+ " response = restobj.get(manager_path)\n",
+ " ethernet_rsp = restobj.get(response.dict[\"links\"][\"EthernetNICs\"][\"href\"])\n",
+ " for item in ethernet_rsp.dict[\"Items\"]:\n",
+ " if not item[\"IPv4Addresses\"][0][\"Address\"] == \"0.0.0.0\":\n",
+ " sys.stdout.write(\"\\t\" + item[\"IPv4Addresses\"][0][\"Address\"] + \"\\n\")\n",
+ " sys.stdout.write(\"%s\" % response)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "31a0442e",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
3.The following code establishes a connection to an HPE iLO server using the HPE iLO REST API.
It sets up the necessary parameters for either local or remote server connection, creates a REST client object, logs into the iLO server, executes an example function to retrieve registry information, and logs out from the server.
\n",
+ "This code demonstrates a simple implementation to retrieve the IP address of an HPE iLO server locally. It initializes the necessary variables, creates a REST client object, logs in to the server, retrieves and prints the IP address, and finally logs out. This example showcases the usage of the HPE iLO REST API for basic server interaction."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3635fca2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " SYSTEM_URL = None\n",
+ " LOGIN_ACCOUNT = None\n",
+ " LOGIN_PASSWORD = None\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 52: Get iLO IP locally\\n\")\n",
+ " get_ilo_ip(REST_OBJ)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/nic_network/get_ilo_nic.ipynb b/example_jupyter_notebooks/nic_network/get_ilo_nic.ipynb
new file mode 100644
index 0000000..8a7c8be
--- /dev/null
+++ b/example_jupyter_notebooks/nic_network/get_ilo_nic.ipynb
@@ -0,0 +1,194 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a9af3f38",
+ "metadata": {},
+ "source": [
+ "
Retrieving the NIC configuration of HPE iLO server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7a1d48e",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a18ac193",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "106fb981",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
\n",
+ "
2. Below is the get_ilo_nic function. The get_ilo_nic function is responsible for retrieving the network interface card (NIC) configuration of an HPE iLO server.
It takes a REST object and a parameter indicating whether to retrieve active or inactive NICs as input. Here's a brief overview of the function's steps:
\n",
+ "
The function first obtains the resource directory of the iLO server using the provided REST object. This directory contains information about the server's available resources, including the NICs.
\n",
+ "
It then searches for the NIC-related information within the resource directory by iterating through the instances and identifying the ones related to the server's manager.\n",
+ "Using the obtained NIC information, the function retrieves the NIC configuration data from the server.
\n",
+ "
Depending on the value of the get_active parameter, the function filters the retrieved NICs to either active or inactive ones.
\n",
+ "
Finally, the function outputs the relevant NIC information, including the NIC's self URL and its JSON representation.
\n",
+ "
In summary, the get_ilo_nic function allows you to fetch and categorize the NIC configuration of an HPE iLO server based on its active or inactive status. This information can be useful for monitoring and managing your server's network settings.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ilo_nic(restobj, get_active):\n",
+ " resource_instances = get_resource_directory(restobj)\n",
+ " if resource_instances:\n",
+ " #Get URI from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if \"Manager.\" in instance.Type:\n",
+ " manager_path = instance.href\n",
+ " break\n",
+ "\n",
+ " tmp = restobj.get(manager_path)\n",
+ " response = restobj.get(tmp.dict[\"links\"][\"EthernetNICs\"][\"href\"])\n",
+ "\n",
+ " for nic in response.dict[\"Items\"]:\n",
+ " if get_active and nic[\"Status\"][\"State\"] == \"Enabled\":\n",
+ " sys.stdout.write(\"Active\\t\" + nic[\"links\"][\"self\"][\"href\"] + \\\n",
+ " \": \" + json.dumps(nic) + \"\\n\")\n",
+ " elif get_active == False and nic[\"Status\"][\"State\"] == \"Disabled\":\n",
+ " sys.stdout.write(\"InActive\\t\" + nic[\"links\"][\"self\"][\"href\"] + \\\n",
+ " \": \" + json.dumps(nic) + \"\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "83ddff83",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
\n",
+ "
3. The overview of main function.
\n",
+ "This script establishes a connection to an HPE iLO server using the provided URL, login account, and password. It then logs in to the server and retrieves the NIC configuration. The script specifically fetches active NICs and displays their information. Finally, it logs out from the server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "40b40d9f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 20: Get iLO's NIC configuration\\n\")\n",
+ " get_ilo_nic(REST_OBJ, True)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/nic_network/set_active_ilo_nic.ipynb b/example_jupyter_notebooks/nic_network/set_active_ilo_nic.ipynb
new file mode 100644
index 0000000..e0299c5
--- /dev/null
+++ b/example_jupyter_notebooks/nic_network/set_active_ilo_nic.ipynb
@@ -0,0 +1,295 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "
Setting the active Manager NIC
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
setting the active Manager NIC As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is about set_active_ilo_nic function
\n",
+ " \n",
+ "\n",
+ "1. This function is used to enable/disable Ethernet interfaces on an iLO (Integrated Lights Out) management interface.
\n",
+ "
\n",
+ " \n",
+ "2. The function first gets a list of available Ethernet interfaces using the Redfish API, which is a standard RESTful interface for managing servers.
\n",
+ "
\n",
+ "\n",
+ "3. The function first gets a list of available Ethernet interfaces using the Redfish API, which is a standard RESTful interface for managing servers.
\n",
+ "
\n",
+ "\n",
+ "4. If the PATCH request is successful (HTTP status 200), the function prints a success message and the response body, which contains information about the updated Ethernet interface.
\n",
+ "
\n",
+ "5. Finally, the function reminds the user that they need to reset iLO for the change to take effect.
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_active_ilo_nic(_redfishobj):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " for interface in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Management Inteface \\'%s\\'\\n\" % ethernet_data\\\n",
+ " [interface].get('Id'))\n",
+ " sys.stdout.write(\"\\t\\'Interface Enabled\\': %s\\n\" % ethernet_data[interface].\\\n",
+ " get('InterfaceEnabled'))\n",
+ "\n",
+ " for ethernet in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Interface: %s\\n\" % ethernet)\n",
+ " ans = input(\"Would you like to enable/disable this interface? (enable/disable)\\n\")\n",
+ " if \"en\" in ans:\n",
+ " body = {\"InterfaceEnabled\": True}\n",
+ " else:\n",
+ " body = {\"InterfaceEnabled\": False}\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! You will need to reset iLO for this change to take effect.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_active_ilo_nic(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "316c3f0e",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/nic_network/set_ethernet_management.ipynb b/example_jupyter_notebooks/nic_network/set_ethernet_management.ipynb
new file mode 100644
index 0000000..76025d8
--- /dev/null
+++ b/example_jupyter_notebooks/nic_network/set_ethernet_management.ipynb
@@ -0,0 +1,315 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ce3836a6",
+ "metadata": {},
+ "source": [
+ "
Setting the IP configuration for the Manager ethernet interface
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a08886ac",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9342022c",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9e2d3008",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f2c9a2c6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The following code defines the set_ilo_static_ipv4 function. This function is used to set the static IPv4 configuration for the Manager ethernet interface in an iLO (Integrated Lights-Out) server.
\n",
+ "\n",
+ "1. Retrieve the resource directory to find the URI for the ethernet interfaces or manually search for the relevant URI if the resource directory is disabled.\n",
+ "2. Retrieve the current configuration of the ethernet interfaces, including DHCPv4 settings, IPv4 addresses, and static name servers, and display them.\n",
+ "3. Iterate through each ethernet interface and prompt the user to choose which interface to modify.\n",
+ "4. Disable the UseDNSServers and UseGateway options if they are enabled in the DHCPv4 settings.\n",
+ "5. Update the IPv4Addresses and StaticNameServers with the provided values in the function parameters, or create a new body with the DNS servers if StaticNameServers are not available.\n",
+ "6. Send a PATCH request to update the ethernet interface configuration with the new settings.\n",
+ "Call the ilo_response function to handle the response and display any error messages or the updated configuration.\n",
+ "7. Exit the loop after processing the first ethernet interface.
\n",
+ "Overall, the function retrieves the current ethernet interface configuration, allows the user to choose which interface to modify, and updates the configuration with the provided IPv4 and DNS settings.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38d43c16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ilo_static_ipv4(_redfishobj, ipv4_dict, dns_dict):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " for interface in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Management Inteface \\'%s\\'\\n\" % ethernet_data\\\n",
+ " [interface].get('Id'))\n",
+ "\n",
+ " sys.stdout.write(\"\\'DHCPv4\\':\\n\")\n",
+ " if ethernet_data[interface].get('DHCPv4'):\n",
+ " print(json.dumps(ethernet_data[interface].get('DHCPv4'), indent=4, sort_keys=True))\n",
+ " else:\n",
+ " print(json.dumps(ethernet_data[interface]['Oem']['Hpe'].get('DHCPv4'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stdout.write(\"\\'IPv4\\':\\n\")\n",
+ " if ethernet_data[interface].get('IPv4StaticAddresses'):\n",
+ " print(json.dumps(ethernet_data[interface].get('IPv4Addresses'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stdout.write(\"\\'StaticNameServers\\':\\n\")\n",
+ " if ethernet_data[interface].get('StaticNameServers'):\n",
+ " print(json.dumps(ethernet_data[interface].get('StaticNameServers'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ "\n",
+ " for ethernet in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Interface: %s\\n\" % ethernet)\n",
+ " ans = input(\"Would you like to modify this interface? (y/n)\\n\")\n",
+ " if \"n\" in ans:\n",
+ " continue\n",
+ " if 'DHCPv4' in ethernet_data[ethernet]:\n",
+ " if ethernet_data[ethernet]['DHCPv4'].get('UseDNSServers'):\n",
+ " resp = _redfishobj.patch(ethernet, {\"DHCPv4\": {\"UseDNSServers\": False}})\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " if ethernet_data[ethernet]['DHCPv4'].get('UseGateway'):\n",
+ " resp = _redfishobj.pathc(ethernet, {\"DHCPv4\": {\"UseGateway\": False}})\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " if 'IPv4StaticAddresses' in ethernet_data[ethernet]:\n",
+ " body.update({\"IPv4Addresses\": [ipv4_dict]})\n",
+ " if 'StaticNameServers' in ethernet_data[ethernet]:\n",
+ " body.update({\"StaticNameServers\" : [dns_dict.get('PrimaryDNS'), \\\n",
+ " dns_dict.get('SecondaryDNS')]})\n",
+ " else:\n",
+ " body.update({\"Oem\": {\"Hpe\": {\"IPv4\": {\"DNSServers\": [dns_dict.get('PrimaryDNS'), \\\n",
+ " dns_dict.get('SecondaryDNS')]}}}})\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "931b2c3b",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ "
The following code defines the ilo_response function. This function is used to handle the response from an iLO (Integrated Lights-Out) server after sending a PATCH request to update the configuration.
\n",
+ "1. Check if the response status is 400. If it is, try to access the extended error message from the response object and print it in a formatted JSON representation.\n",
+ "2. If an exception occurs while accessing the extended error message, print a generic error message indicating that the extended message info cannot be accessed.\n",
+ "3. If the response status is not 400 (indicating an error), write a stderr message indicating the HTTP response status.\n",
+ "4. If the response status is 200 (indicating success), print a success message suggesting to reset iLO for the settings to take effect.\n",
+ "5. Print the response dictionary in a formatted JSON representation.\n",
+ "
\n",
+ "Overall, the function retrieves the current ethernet interface configuration, allows the user to choose which interface to modify, and updates the configuration with the provided IPv4 and DNS settings.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7aa4cac1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ilo_response(_redfishobj, resp):\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! Suggest to reset iLO for settings to take effect.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d848c57",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
4.
\n",
+ " \n",
+ "Next is the main function. The code establishes a connection with a target server using Redfish, a standardized API for server management. It sets the URL, login credentials, and defines dictionaries for IPv4 and DNS settings. It creates a Redfish client object and attempts to log in using the provided credentials. If successful, it calls the set_ilo_static_ipv4 function to configure the IPv4 and DNS settings for a specific Ethernet interface on the server. The function retrieves the necessary information, displays the current settings, and prompts the user to choose an interface for modification. If selected, it updates the DHCPv4 and IPv4 static address settings based on the provided dictionaries and sends the changes to the server. Finally, the code logs out of the Redfish session.\n",
+ "
\n",
+ "In summary, the code establishes a connection with a server, configures network settings using Redfish, and performs the necessary operations to modify the IPv4 and DNS settings for a specific Ethernet interface on the server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e5ac50fc",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "40aabbdc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #IPv4 settings for Address, Gateway and SubnetMask as well as DNS.\n",
+ " IPV4_DICT = {'Address':'16.83.61.123', \\\n",
+ " 'Gateway':'16.83.60.1', \\\n",
+ " 'SubnetMask':'255.255.252.0' \\\n",
+ " }\n",
+ " DNS_DICT = {'PrimaryDNS':'16.110.135.52', \\\n",
+ " 'SecondaryDNS':'16.110.135.51' \\\n",
+ " }\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ilo_static_ipv4(REDFISHOBJ, IPV4_DICT, DNS_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90b4cb56",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ntp_timezone/enabling_ntp_server.ipynb b/example_jupyter_notebooks/ntp_timezone/enabling_ntp_server.ipynb
new file mode 100644
index 0000000..656cc07
--- /dev/null
+++ b/example_jupyter_notebooks/ntp_timezone/enabling_ntp_server.ipynb
@@ -0,0 +1,309 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# ENABLING NTP SERVER "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
enable ntp servers . As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2
\n",
+ "Below function describes the process how to enable NTP servers for HPE ilo systems. NTP or Network Time Protocol is an internet protocol used to synchronize with computer clokc time sources in a network. \n",
+ "Current cell is the explains the processes performed inside the below function.\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. Initially, to obtain NTP server related information for HPE ilo systems a series of HTTP GET requests are being made so as to navigate to that path inside the iLO rest api where required information is stored.\n",
+ "After completion of these get requests we will be having the relevant uri in
manager_ethernet_interfaces_members.\n",
+ "
\n",
+ "2. Else if
resource directory is enabled we can just use the resource directory to and then again navigate through the api to find relevant uri.\n",
+ "
\n",
+ " \n",
+ "3. Whatever changes need to be made to enable the NTP server are being enclosed inside the dictionary named as
body. Next up for all the instances of ethernet in ethernet_data we simply make a
HTTP PATCH request by passing the ethernet instance and body dictionary with the PATCH request. \n",
+ " \n",
+ "\n",
+ "4. Following the patch request, the response returned by server is being saved inside resp variable and later if the server returns proper response it means there is no error else error is returned with error information. A reference for json.dumps\n",
+ "function as it is used multiple times -
click here.\n",
+ "\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_ntp(_redfishobj, ntp_servers, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " print(json.dumps(ethernet_data, indent=4, sort_keys=True))\n",
+ "\n",
+ " body = {\"Oem\": {\"Hpe\": {\"DHCPv4\": {\"UseNTPServers\": ntp_servers}, \\\n",
+ " \"DHCPv6\": {\"UseNTPServers\": ntp_servers}}}}\n",
+ " for ethernet in ethernet_data:\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " _data = _redfishobj.get(ethernet).dict\n",
+ " sys.stdout.write(\"\\nShowing \\'%s\\' interface after changes:\\n\" % ethernet)\n",
+ " print(json.dumps(_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to enable_ntp function by passing parameters such as redfishclient object and enable flag to perform required operation.
\n",
+ "- After getting required information Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'ilorest'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mgetpass\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m redfish_client\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mredfish_object\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m RedfishClient\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mexceptions\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ServerDownOrUnreachableError\n",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'ilorest'"
+ ]
+ }
+ ],
+ "source": [
+ "import getpass\n",
+ "from ilorest import redfish_client\n",
+ "from ilorest.redfish_object import RedfishClient\n",
+ "from ilorest.exceptions import ServerDownOrUnreachableError\n",
+ "\n",
+ "def main():\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n",
+ "if __name__ == \"__main__\":\n",
+ " main()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/example_jupyter_notebooks/ntp_timezone/set_ilo_ntp_servers.ipynb b/example_jupyter_notebooks/ntp_timezone/set_ilo_ntp_servers.ipynb
new file mode 100644
index 0000000..34ea8b5
--- /dev/null
+++ b/example_jupyter_notebooks/ntp_timezone/set_ilo_ntp_servers.ipynb
@@ -0,0 +1,281 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "57e65617",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Setting NTP Servers for HPE iLO Systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9872b27b",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b31c3490",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "from reset_ilo import reset_ilo\n",
+ "from enable_ntp_servers import enable_ntp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7ca0d0e7",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The script begins by defining the necessary dependencies and helper functions. The set_ilo_ntp_servers function is responsible for updating the NTP server settings for the iLO system.
\n",
+ "
Steps involved are:
\n",
+ "\n",
+ "1. The function set_ilo_ntp_servers sets the NTP (Network Time Protocol) servers for an HPE iLO system. It first retrieves the URI for the date and time service using the get_resource_directory function. If the resource directory is disabled or not available, it finds the URI by traversing the managers' hierarchy.\n",
+ "\n",
+ "2. Once the URI is obtained, the function sends a GET request to retrieve the current NTP server settings. If the StaticNTPServers property is present, it sends a PATCH request to update the NTP server list with the provided ntp_server_list.\n",
+ "\n",
+ "3. If any error occurs during the process, the function handles it accordingly. If the response status is 400, it attempts to access the iLO extended error information and prints it. If the response status is not 200 or 400, it prints an error message.\n",
+ "\n",
+ "4. If the NTP server update is successful, it prints a success message and the updated NTP server information.\n",
+ "\n",
+ "
\n",
+ "In summary, the function retrieves the URI for the date and time service, updates the NTP server settings, and handles any errors that may occur during the process.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ilo_ntp_servers(_redfishobj, ntp_server_list):\n",
+ "\n",
+ " date_time_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " date_time_uri = managers_members_response.obj.Oem.Hpe.Links['DateTimeService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLODateTime.' in instance['@odata.type']:\n",
+ " date_time_uri = instance['@odata.id']\n",
+ "\n",
+ " if date_time_uri:\n",
+ " data = _redfishobj.get(date_time_uri)\n",
+ " if data.dict.get('StaticNTPServers'):\n",
+ " resp = _redfishobj.patch(date_time_uri, {'StaticNTPServers': ntp_server_list})\n",
+ " else:\n",
+ " raise Exception(\"\\'StaticNTPServers\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " ntp_data = _redfishobj.get(date_time_uri).dict.get('StaticNTPServers')\n",
+ " print(\"Printing updated NTP Servers:\\n\")\n",
+ " print(json.dumps(ntp_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e339e770",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " The following code defines the give_client function, which creates a client object and performs the login operation through the following steps:
\n",
+ "1. The function give_client creates a Redfish client object by instantiating the RedfishClient class. It provides the base URL, username, and password for the Redfish service as parameters.\n",
+ "\n",
+ "2. The function attempts to log in to the Redfish service using the created client object. It sends the login request with the provided credentials.\n",
+ "\n",
+ "3. If the login is successful, the function returns the instantiated Redfish client object. If there is an error connecting to the server or if the server does not support Redfish, an error message is printed, and the program exits.\n",
+ "
\n",
+ "In summary, the give_client function creates a Redfish client object, performs the login process, and returns the client object if the login is successful.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a963c789",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def give_client():\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " rf_obj = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " rf_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " return rf_obj"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "19988f86",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
4.
\n",
+ " This is Main function overview.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " The main section of the script sets the system URL, login account, and password. It creates a Redfish client object, logs in to the iLO system, enables NTP servers for the primary iLO management interface, resets the iLO, and waits for 60 seconds. Afterward, it logs out, creates a new Redfish client object, and calls the set_ilo_ntp_servers function to configure the NTP servers using the specified list. Finally, it logs out again.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "07bae030",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # logfile path and filename\n",
+ " LOGFILE = input(\"Enter log file path and file name: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ahs_data(REDFISHOBJ, LOGFILE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c4b94a35",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/ntp_timezone/set_ilo_timezone.ipynb b/example_jupyter_notebooks/ntp_timezone/set_ilo_timezone.ipynb
new file mode 100644
index 0000000..7725c00
--- /dev/null
+++ b/example_jupyter_notebooks/ntp_timezone/set_ilo_timezone.ipynb
@@ -0,0 +1,242 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e9c3d898",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Setting the timezone for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "929300c6",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ef56c73",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library tp set up the ilo NTP server!
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6a1ae9ce",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The function set_timezone is defined below. It provides a convenient way to set the timezone for an HPE iLO system using the Redfish API, utilizing the resource directory or direct URI retrieval methods to locate the relevant DateTime service and perform the timezone update.
\n",
+ "
Here's a summary of the function:
\n",
+ "\n",
+ "1.
Resource Directory Retrieval: The function retrieves the resource directory information using the _redfishobj Redfish client object. If the resource directory is not available or the DISABLE_RESOURCE_DIR flag is set, it retrieves the URI for the DateTime service from the server's Managers and Members resources.\n",
+ "\n",
+ "2.
Finding the Relevant URI: If the resource directory is available, the function searches for the relevant URI for the DateTime service within the resource instances. It looks for an instance with the '#HpeiLODateTime.' substring in its @odata.type.\n",
+ "\n",
+ "3.
Updating the Timezone: After obtaining the DateTime service URI, the function sends a GET request to retrieve the current data for the service. If the retrieved data contains the 'TimeZone' property, it constructs a JSON payload to update the timezone to the specified value. A PATCH request is then sent to the DateTime service URI with the timezone payload to modify the timezone.\n",
+ "\n",
+ "4.
Handling Responses: The function handles different response scenarios. If the response status code is 400, indicating a client-side error, it attempts to print the extended error information and the available timezone list. For response status codes other than 200 or 201, indicating an HTTP error, an appropriate error message is printed. If the response status is 200, indicating a successful update, the function prints a success message along with the updated timezone information.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_timezone(_redfishobj, timezone):\n",
+ "\n",
+ " date_time_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " date_time_uri = managers_members_response.obj.Oem.Hpe.Links['DateTimeService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLODateTime.' in instance['@odata.type']:\n",
+ " date_time_uri = instance['@odata.id']\n",
+ "\n",
+ " if date_time_uri:\n",
+ " data = _redfishobj.get(date_time_uri)\n",
+ " if data.dict.get('TimeZone'):\n",
+ " _data = {'TimeZone': {\"Name\": timezone}}\n",
+ " resp = _redfishobj.patch(date_time_uri, _data)\n",
+ " else:\n",
+ " raise Exception(\"\\'TimeZone\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " print(json.dumps(data.obj.get('TimeZoneList'), indent=4, sort_keys=True))\n",
+ " sys.stderr.write(\"Check the TimeZone value...\\n\")\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " ntp_data = _redfishobj.get(date_time_uri).dict.get('TimeZone')\n",
+ " print(\"Printing updated NTP Servers:\\n\")\n",
+ " print(json.dumps(ntp_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b943b2e",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " This is Main function overview.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " The main section of the script proceeds to create a Redfish client object using the specified system URL, login account, and password. This client object allows communication with the remote system via Redfish APIs. After successfully creating the client object, it logs in to the system to establish an authenticated session.\n",
+ "
\n",
+ "If any server connectivity issues occur or the server does not support RedFish, an error message is displayed, and the script exits. Otherwise, the set_timezone function is called, passing the Redfish client object and the desired timezone value as parameters. This function handles the task of setting the timezone on the system using the Redfish API.\n",
+ "
\n",
+ "Upon completion, the script logs out from the system, terminating the authenticated session.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb9dca1",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #timezone property (review the list of timezones ('TimeZoneList') within the DateTime URI.\n",
+ " TIMEZONE = \"US/Central\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_timezone(REDFISHOBJ, TIMEZONE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0e4573cc",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/power/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb b/example_jupyter_notebooks/power/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb
new file mode 100644
index 0000000..8c21f3f
--- /dev/null
+++ b/example_jupyter_notebooks/power/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb
@@ -0,0 +1,256 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "
Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/power/get_powermetrics_average.ipynb b/example_jupyter_notebooks/power/get_powermetrics_average.ipynb
new file mode 100644
index 0000000..8c21f3f
--- /dev/null
+++ b/example_jupyter_notebooks/power/get_powermetrics_average.ipynb
@@ -0,0 +1,256 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "
Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/redfish operation and utility/ilorest_util.ipynb b/example_jupyter_notebooks/redfish operation and utility/ilorest_util.ipynb
new file mode 100644
index 0000000..986d076
--- /dev/null
+++ b/example_jupyter_notebooks/redfish operation and utility/ilorest_util.ipynb
@@ -0,0 +1,183 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
ilorest_util As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "
2.
This is our get_resource_directory function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present.\n",
+ "
\n",
+ "1.Using the phrase redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id'], it attempts to retrieve the resource directory URI. The resource directory is not accessible on non-HPE servers if the key @odata.id is missing from the ResourceDirectory dictionary. Then, a message indicating the error is printed, and None is returned.\n",
+ "
\n",
+ "2.Redfishobj.get(resource_uri) is used by the code to send a GET request to the resource directory URI if it was successfully fetched.\n",
+ "
\n",
+ "3.Then we extracts the list of resource instances from the response dictionary (response.dict[\"Instances\"]) and assigns it to the resources variable if the response status is 200 (OK), which means that the resource directory was found at the specified URI (/redfish/v1/resourcedirectory).\n",
+ "
\n",
+ "4.If the response status is not 200, an error message is printed, indicating that the resource directory is missing at the specified URI.\n",
+ "
\n",
+ "5.Atlast the function return the list of resources.\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_resource_directory(redfishobj):\n",
+ "\n",
+ " try:\n",
+ " resource_uri = redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id']\n",
+ " except KeyError:\n",
+ " sys.stderr.write(\"Resource directory is only available on HPE servers.\\n\")\n",
+ " return None\n",
+ "\n",
+ " response = redfishobj.get(resource_uri)\n",
+ " resources = []\n",
+ "\n",
+ " if response.status == 200:\n",
+ " sys.stdout.write(\"\\tFound resource directory at /redfish/v1/resourcedirectory\" + \"\\n\\n\")\n",
+ " resources = response.dict[\"Instances\"]\n",
+ " else:\n",
+ " sys.stderr.write(\"\\tResource directory missing at /redfish/v1/resourcedirectory\" + \"\\n\")\n",
+ "\n",
+ " return resources"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "This is the overview of the get_gen function .\n",
+ "
\n",
+ "
\n",
+ " - It starts by accessing the root object of the Redfish API response using _redfishobj.root.obj.
\n",
+ " - Determines whether the response has the key Hpe or Hp beneath the Oem key. If so, it is assumed to be an HPE or HP server.
\n",
+ " - Based on the value of gencompany, it initialises the comp variable. Comp sets to 'Hp' if gencompany is True; otherwise, it stays None.Additionally, it looks for the key 'Hpe' under the 'Oem' key in the response. If so, it changes comp to 'Hpe'.
\n",
+ " - The code verifies whether the key ManagerType under the Manager key of the Oem dictionary is present in the response. If so, it gets the ManagerType value, which stands for the generation of the iLO.
\n",
+ " - The ManagerFirmwareVersion key is also used to access the iLO firmware version .Ilogen is set to 4 and iloversion is set to None if the iLO generation terminates in CM.
\n",
+ " - The second element is used as the iLO generation number once the iLO generation string has been divided by spaces. Additionally, it adds a dot to the final component of the iLO firmware version to create the iLO version number.
\n",
+ " - It returns a tuple (ilogen, iloversion) containing the determined iLO generation and version.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_gen(_redfishobj):\n",
+ "\trootresp = _redfishobj.root.obj\n",
+ "\t#Default iLO 5\n",
+ "\tilogen = 5\n",
+ "\tgencompany = next(iter(rootresp.get(\"Oem\", {}).keys()), None) in ('Hpe', 'Hp')\n",
+ "\tcomp = 'Hp' if gencompany else None\n",
+ "\tcomp = 'Hpe' if rootresp.get(\"Oem\", {}).get('Hpe', None) else comp\n",
+ "\tif comp and next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tget('ManagerType', None):\n",
+ "\t\tilogen = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {})))\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.get(\"ManagerType\")\n",
+ "\t\tilover = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t get(\"ManagerFirmwareVersion\")\n",
+ "\t\tif ilogen.split(' ')[-1] == \"CM\":\n",
+ "\t\t\t# Assume iLO 4 types in Moonshot\n",
+ "\t\t\tilogen = 4\n",
+ "\t\t\tiloversion = None\n",
+ "\t\telse:\n",
+ "\t\t\tilogen = ilogen.split(' ')[1]\n",
+ "\t\t\tiloversion = float(ilogen.split(' ')[-1] + '.' + \\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t''.join(ilover.split('.')))\n",
+ "\treturn (ilogen, iloversion)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "
4.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/redfish operation and utility/quickstart_redfish.ipynb b/example_jupyter_notebooks/redfish operation and utility/quickstart_redfish.ipynb
new file mode 100644
index 0000000..c1230f0
--- /dev/null
+++ b/example_jupyter_notebooks/redfish operation and utility/quickstart_redfish.ipynb
@@ -0,0 +1,168 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Quickstart_redfish"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Quickstart-redfish As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "658962be-a0df-4696-ab9e-73f844703ff9",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "53341fc4-f674-4781-bcb1-04bb06d3d1fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import redfish\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
Code overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " 1.When you are running server locally the login and password will be None.\n",
+ "
\n",
+ " 2.When server is running in remotely connect using iLO account name and iLO address then iLO host and login credentials.\n",
+ "
\n",
+ " 3.Creating redfish object which will use to communicate with the server.\n",
+ "
\n",
+ " 4.By using redfish object we can login to server and start the session.\n",
+ "
\n",
+ " 5.Next we make a http request to retrive the information about a system and printing the respone.\n",
+ "
\n",
+ " 6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# When running on the server locally use the following commented values\n",
+ "# iLO_host = \"blobstore://.\"\n",
+ "# LOGIN_ACCOUNT = \"None\"\n",
+ "# LOGIN_PASSWORD = \"None\"\n",
+ "\n",
+ "# When running remotely connect using the iLO address, iLO account name, \n",
+ "# and password to send https requests\n",
+ "iLO_host = \"https://10.0.0.100\"\n",
+ "login_account = \"admin\"\n",
+ "login_password = \"password\"\n",
+ "\n",
+ "## Create a REDFISH object\n",
+ "REDFISH_OBJ = redfish.RedfishClient(base_url=iLO_host,username=login_account, \\\n",
+ " password=login_password)\n",
+ "\n",
+ "# Login into the server and create a session\n",
+ "REDFISH_OBJ.login()\n",
+ "\n",
+ "# Do a GET on a given path\n",
+ "response = REDFISH_OBJ.get(\"/redfish/v1/systems/1\")\n",
+ "\n",
+ "# Print out the response\n",
+ "sys.stdout.write(\"%s\\n\" % response)\n",
+ "\n",
+ "# Logout of the current session\n",
+ "REDFISH_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0ded655-d8e4-452d-b181-783a6b1788f5",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/security_certificate/enable_secure_boot.ipynb b/example_jupyter_notebooks/security_certificate/enable_secure_boot.ipynb
new file mode 100644
index 0000000..3bcdf99
--- /dev/null
+++ b/example_jupyter_notebooks/security_certificate/enable_secure_boot.ipynb
@@ -0,0 +1,250 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b44c9aad",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
enabling secure boot As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "74ee46a2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below
\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3b9ca27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0e073c6",
+ "metadata": {},
+ "source": [
+ "
2.
This is our enable_secure_boot function overview, in the end this will give us with secure boot related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the secure boot information.\n",
+ "\n",
+ "1. In the
enable_secure_boot function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about secureboot is stored inside the
systems json object.\n",
+ " Through systems_response variable we are making a http
GET operation to and trying to obtain the secure boot about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the systems response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
systems_members_response.\n",
+ " The secure boot information is ultimately present in the
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if secure boot is present in
@odata.type attribute then we will store information about secure boot in secure_boot_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if secure_boot_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8d60549e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_secure_boot(_redfishobj, secure_boot_enable):\n",
+ "\n",
+ " secure_boot_uri = None\n",
+ " secure_boot_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " secure_boot_uri = systems_members_response.obj['SecureBoot']['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#SecureBoot.' in instance['@odata.type']:\n",
+ " secure_boot_uri = instance['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ "\n",
+ " if secure_boot_data:\n",
+ " print(\"\\n\\nShowing Secure Boot properties before changes:\\n\\n\")\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if secure_boot_uri:\n",
+ " body = {'SecureBootEnable': secure_boot_enable}\n",
+ " resp = _redfishobj.patch(secure_boot_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\n\\nShowing Secure Boot properties after changes:\\n\\n\")\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b227f8f6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
The Main function:
\n",
+ "
Please enter your login credentials here to proceed further:
\n",
+ "
\n",
+ " - Once your credentials are entered, a Redfish object is created with the help of the RedfishClient class, and a session is created to log you in to the server.
\n",
+ " - If the server is down or unreachable, we get a \"server not reachable\" message.
\n",
+ " - If not, we make a call to the enable_secure_boot function to obtain secure boot-related information of the system.
\n",
+ " - After getting the required information, Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8028b4ff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #Properties:\n",
+ " #secure boot enable property\n",
+ " SECURE_BOOT_ENABLE = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_secure_boot(REDFISHOBJ, SECURE_BOOT_ENABLE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28cb201c",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf8a164b",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/security_certificate/generate_csr.ipynb b/example_jupyter_notebooks/security_certificate/generate_csr.ipynb
new file mode 100644
index 0000000..83a9be5
--- /dev/null
+++ b/example_jupyter_notebooks/security_certificate/generate_csr.ipynb
@@ -0,0 +1,279 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "042acf39",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Generating a certificate signing request for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b34599c",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
generate_csr!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7338dfb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0c9837f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "034daf66",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
This is our generate csr function overview, in the end we will be able to make a certificate signing request.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
generate_csr function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about Http certificates is stored inside the
managers json object.\n",
+ " And now through managers_response variable, we are making a http
GET operation to and trying to obtain the certificates of signing of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system managers members response object with different
odata_id we get a security service uri .\n",
+ " Then again an http GET request is made and response is stored in
security_service_response.\n",
+ " Then we will make a http_cert_response by using csr_uri through security_service_response and then using http_cert_response we will get
generate_csr_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeHttpsCert attribute is present in
@odata.type attribute then we'll set csr_uri and
get generate csr uri of the target.\n",
+ "
\n",
+ "\n",
+ "5. If
generate_csr_uri exists, then we will define the body and send a
post request through redfish object. After generating the csr, we can obtain the
csr_response using
get method for csr_uri.
csr_response contains
CertificateSigningRequest. \n",
+ "\n",
+ "
\n",
+ "6. If you get the result, then it is successful. if you don't get the result, then there is an error.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "644bd708",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_csr(_redfishobj, csr_file, csr_properties):\n",
+ "\n",
+ " csr_uri = None\n",
+ " generate_csr_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " csr_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " https_cert_response = _redfishobj.get(csr_uri)\n",
+ " generate_csr_uri = https_cert_response.obj['Actions']['#HpeHttpsCert.GenerateCSR']\\\n",
+ " ['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " csr_uri = instance['@odata.id']\n",
+ " generate_csr_uri = _redfishobj.get(csr_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " break\n",
+ "\n",
+ " if generate_csr_uri:\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.GenerateCSR\"\n",
+ " body[\"City\"] = csr_properties[\"City\"]\n",
+ " body[\"CommonName\"] = csr_properties[\"CommonName\"]\n",
+ " body[\"Country\"] = csr_properties[\"Country\"]\n",
+ " body[\"OrgName\"] = csr_properties[\"OrgName\"]\n",
+ " body[\"OrgUnit\"] = csr_properties[\"OrgUnit\"]\n",
+ " body[\"State\"] = csr_properties[\"State\"]\n",
+ " resp = _redfishobj.post(generate_csr_uri, body)\n",
+ " if resp.status in [200, 201]:\n",
+ " sys.stdout.write(\"Generating CSR, this may take a few minutes\\n\")\n",
+ " sys.stdout.write(\"Sleeping for 5 minutes...\\n\")\n",
+ " time.sleep(600)\n",
+ " csr_resp = _redfishobj.get(csr_uri).dict['CertificateSigningRequest']\n",
+ " with open(csr_file, 'wb') as csroutput:\n",
+ " csroutput.write(csr_resp)\n",
+ " sys.stdout.write(\"CSR Data saved to file: '%s'\\n\" % csr_file)\n",
+ " else:\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status not in [200, 201]:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2da11ba0",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter your ilo url,Username,Password here.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call generate_csr with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46b3e899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #CSR Dictionary, each value should be updated to reflect the desired CSR\n",
+ " CSR_DICT = {\"City\" : input(\"Enter city:\"), \"CommonName\": input(\"Enter name:\"), \"Country\": input(\"Enter country :\"), \\\n",
+ " \"OrgName\": input(\"Enter organization :\"), \"OrgUnit\": input(\"Enter unit :\"), \"State\": input(\"Enter state:\")}\n",
+ "\n",
+ " #After CSR is generated, a file will be created and the CSR will be downloaded\n",
+ " CSR_FILE = \"csr.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " generate_csr(REDFISHOBJ, CSR_FILE, CSR_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06934cbc",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12c33902",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/security_certificate/import_ssl.ipynb b/example_jupyter_notebooks/security_certificate/import_ssl.ipynb
new file mode 100644
index 0000000..a0c2097
--- /dev/null
+++ b/example_jupyter_notebooks/security_certificate/import_ssl.ipynb
@@ -0,0 +1,257 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "4bff53aa",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Import_ssl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d4e9abe",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
importing secure socket layer As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76d83083",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - getpass
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "a54980c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5ca097d3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2
\n",
+ "This cell gives overview about of the function SSL(secure socket layer)\n",
+ "
\n",
+ "1. It will retrieves the URI for the security service, sends a GET request to retrieve the security service object, and then retrieves the URI for the HTTPS certificate object linked to from the security service object.\n",
+ "
\n",
+ "2. Else it searches the Redfish API resource directory for an instance of a HPE HTTPS certificate object. If found, it retrieves the URI for the HTTPS certificate object and breaks out of the loop.\n",
+ "
\n",
+ "3. If the uri is not none then it retrieves the HTTPS certificate import URI from the HTTPS certificate object and then sends a POST request to import an SSL certificate using the Redfish API. The SSL certificate is passed in the request body.\n",
+ "
\n",
+ "4.Handling the error after inserting the iso image in slot \n",
+ " If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ " If status code is 200 OK then it will print error meassage and status code.\n",
+ " Else the insertion is success then code print result in JSON format and aslo printing the import is successfully done.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "d3002f22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def import_ssl(_redfishobj, ssl_file_path):\n",
+ " # intialize to None\n",
+ " https_cert_uri = None\n",
+ " body = dict()\n",
+ " #Retrieving resource directory instances using Redfish API client.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " https_cert_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " https_cert_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if https_cert_uri:\n",
+ " https_cert_import_uri = _redfishobj.get(https_cert_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.ImportCertificate']['target']\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.ImportCertificate\"\n",
+ " body[\"Certificate\"] = ssl_cert\n",
+ " resp = _redfishobj.post(https_cert_import_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\nImporting SSL Certificate may take a few minutes...\\n \"\\\n",
+ " \"iLO will reset with new changes.\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d911eb18",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3
\n",
+ "
The Main function overview . \n",
+ "
\n",
+ " - When you are running server locally or running in remotely connect using secured connection then you need to enter proper login cerdentials.
\n",
+ " - Creating redfish object and trying to establish connection with server using redfish object.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Read the content of an SSL certificate file at SSL_FILE_PATH.
\n",
+ " - Lastly, Redfishobj.logout logs us out of the system and ends the session.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4a26864f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " SSL_FILE_PATH = \"certificate.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " with open(SSL_FILE_PATH, 'r') as csr_data:\n",
+ " ssl_cert = csr_data.read()\n",
+ " csr_data.close()\n",
+ "\n",
+ " if ssl_cert:\n",
+ " import_ssl(REDFISHOBJ, ssl_cert)\n",
+ " else:\n",
+ " raise Exception(\"Invalid SSL certificate.\\n\")\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29439599",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e838742",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/server_manager/computer_details.ipynb b/example_jupyter_notebooks/server_manager/computer_details.ipynb
new file mode 100644
index 0000000..ee8373c
--- /dev/null
+++ b/example_jupyter_notebooks/server_manager/computer_details.ipynb
@@ -0,0 +1,230 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
Gathering the computer system details
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Welcome to
python-iLOrest-library Here is an example to
get_computer_details!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. We are importing all the necessary modules from the ilorest library!
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is the function to get the computer details requested.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
computer_details function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about computer is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the computer data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if computerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally print the Computer Details through
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def computer_details(_redfishobj):\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " print(\"\\n\\nPrinting computer system details:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " Enter iLO url, Username, Password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, but if Server is not avaialbe we get an error saying \"server unreachable\".
\n",
+ "
\n",
+ "5. Then we call computer_details with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " computer_details(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/server_manager/reboot_server.ipynb b/example_jupyter_notebooks/server_manager/reboot_server.ipynb
new file mode 100644
index 0000000..1dfae9f
--- /dev/null
+++ b/example_jupyter_notebooks/server_manager/reboot_server.ipynb
@@ -0,0 +1,236 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# REBOOTING A SERVER"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
perform rebooting of a server. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2
\n",
+ "In below cell is the reboot_server function.\n",
+ "Current cell is the overview of it, utimately at the end this will reboot the server and provide the response for the same.\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. In the
reboot server function we are first using
system_members_response variable to obtain information about the path at which server related information is stored by using couple of get requests.\n",
+ "
\n",
+ "2. If the resource directory was accessible then we simply search for
'#ComputerSystem' key (as this is the place comprising of server related information inside the
instance['odata.type'] dictionary and finally making a get request to that location.\n",
+ "
\n",
+ " \n",
+ "3. If we obtain systems_response successfully then a
ressettype list is created specifying the parameters that how we want to restart.\n",
+ " \n",
+ "\n",
+ "4. Later both the parameters are passed into a new dictionary named body and post request is created to make changes on the server side.\n",
+ " A successful
HTTP post request will set the values at server end so that a server gets rebooted.\n",
+ " \n",
+ "\n",
+ "5. Lastly, we also save response status inside
resp variable and check what is the status code returned to confirm whether the post request was success or not. If success then response by server is printed and if not then error message is printed.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reboot_server(_redfishobj):\n",
+ "\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj.get_resource_directory)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_uri = instance['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " #code check for determines whether a systems_response object is present, finds the URI for resetting a computer \n",
+ " #system, builds a request body describing the reset action and type, then sends a POST request with the provided \n",
+ " #reset type to restart the system.\n",
+ " if systems_response:\n",
+ " system_reboot_uri = systems_response.obj['Actions']['#ComputerSystem.Reset']['target']\n",
+ " body = dict()\n",
+ " resettype = ['ForceRestart','GracefulRestart']\n",
+ " body['Action'] = 'ComputerSystem.Reset'\n",
+ " for reset in resettype:\n",
+ " if reset.lower() == \"forcerestart\":\n",
+ " body['ResetType'] = \"ForceRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ " elif reset.lower() == \"gracefulrestart\":\n",
+ " body['ResetType'] = \"GracefulRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to reboot_server function to perform rebooting of server.
\n",
+ "- After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " #login credentials\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " #function call\n",
+ " reboot_server(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/example_jupyter_notebooks/server_manager/reset_server.ipynb b/example_jupyter_notebooks/server_manager/reset_server.ipynb
new file mode 100644
index 0000000..9356919
--- /dev/null
+++ b/example_jupyter_notebooks/server_manager/reset_server.ipynb
@@ -0,0 +1,304 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reset_server"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reseting the server!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Declared a global variable i.e; DISABLE_RESOURCE_DIR.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
RedfishClient\n",
+ "
ServerDownOrUnreachableError \n",
+ "
get_resource_directory \n",
+ "
get_gen\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
This is our resetting_server function overview, in the end this function the server get restarted.
\n",
+ "
Let me give you a walk through of it!
\n",
+ " 1.If either of no resource instance or DISABLE_RESOURCE_DIR flag is set then it retrieve the URI for systems from the root object, get the response for the systems URI using the Redfish API object, retrieve the URI for the members from the systems response object, and then get the response for the members URI using the Redfish API object.\n",
+ "
\n",
+ "
\n",
+ " 2.Else i.e;iterates through the resource instances, checking if the
@odata.type value contains ComputerSystem. If found, it assigns the
@odata.id value to
managers_members_uri and retrieves the response using the Redfish API object.\n",
+ "
\n",
+ "
\n",
+ " 3.This code gets the URI for the computer system reset action, builds a dictionary with an action value and reset type, iterates through reset types, then posts the body to the URI for each reset type using the Redfish API object if managers_members_response exists.\n",
+ "
\n",
+ "
\n",
+ " 4.Next is to check the status of the response received from the previous
POST request sent using the Redfish client object
_redfishobj.\n",
+ "
\n",
+ " 1.If the status is 400, it attempts to print the extended error message associated with the response.\n",
+ "
\n",
+ " 2.If the response status is not 400 and not 200, an error message is printed to the standard error stream.\n",
+ "
\n",
+ " 3.If the response status is 200, it indicates that the reset operation was successful. The code then prints a success message and prints the JSON response received from the server in a formatted way.\n",
+ "
\n",
+ "
\n",
+ " 5. Again function call
reset_server_gen9(_redfishobj) uses the Redfish API object to retrieve the response for the managers URI, the response object to retrieve the URI for the computer system reset action, etc. The action value and reset type are created in a dictionary,and the reset type is changed to
ForceRestart after printing the URI.\n",
+ "
\n",
+ " Again the
POST request sent by using RedFish client object is again checked.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_server(_redfishobj):\n",
+ " \n",
+ " managers_members_response = None\n",
+ " #Assigns resource directory to variable using Redfish API object\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " #checking if no resource instance or DISABLE_RESOURCE_DIR flag is set \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if \"ComputerSystem.\" in instance['@odata.type']:\n",
+ " managers_members_uri = instance['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " \n",
+ " if managers_members_response:\n",
+ " path = managers_members_response.obj[\"Actions\"][\"#ComputerSystem.Reset\"][\"target\"]\n",
+ " body = dict()\n",
+ " resettype = ['ForceRestart','GracefulRestart']\n",
+ " body[\"Action\"] = \"ComputerSystem.Reset\"\n",
+ " for reset in resettype:\n",
+ " if reset.lower() == \"forcerestart\":\n",
+ " body['ResetType'] = \"ForceRestart\"\n",
+ " resp = _redfishobj.post(path, body)\n",
+ " elif reset.lower() == \"gracefulrestart\":\n",
+ " body['ResetType'] = \"GracefulRestart\"\n",
+ " resp = _redfishobj.post(path, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " \n",
+ "#creates a dictionary containing an action value and reset type, then posts the dictionary to the \n",
+ "#computer system reset action URI to reset a server using the Redfish API.\n",
+ "def reset_server_gen9(_redfishobj):\n",
+ " \n",
+ " managers_uri = \"/redfish/v1/Systems/1/\"\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " system_path = managers_response.obj[\"Actions\"][\"#ComputerSystem.Reset\"][\"target\"]\n",
+ " print(system_path)\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"Reset\"\n",
+ " body[\"ResetType\"] = \"ForceRestart\"\n",
+ "\n",
+ " resp = _redfishobj.post(system_path, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
The Main function: \n",
+ "
\n",
+ " - After initilize the parser and adds argument such as the iLO IP address, username, and password as three command-line options to the parser. Each argument has a corresponding default value and help text.
\n",
+ " - In try section of code ;utilising the supplied iLO IP address, login, and password, to create a Redfish client object. If the login is successful, the get_gen function is used to check the server generation, and based on the generation number, the proper reset method is selected. The reset_server function is called if the server is a Gen5 server; otherwise, the reset_server_gen9 function is called. An error message is printed to the console and the script terminates if the server cannot be reached or does not support Redfish.
\n",
+ " - REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'argparse' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;18m__name__\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__main__\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# Initialize parser \u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m parser \u001b[38;5;241m=\u001b[39m \u001b[43margparse\u001b[49m\u001b[38;5;241m.\u001b[39mArgumentParser(description \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mScript to upload and flash NVMe FW\u001b[39m\u001b[38;5;124m\"\u001b[39m) \n\u001b[1;32m 5\u001b[0m parser\u001b[38;5;241m.\u001b[39madd_argument(\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-i\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m--ilo\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 10\u001b[0m help\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miLO IP of the server\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 11\u001b[0m default\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[1;32m 12\u001b[0m parser\u001b[38;5;241m.\u001b[39madd_argument(\n\u001b[1;32m 13\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-u\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 14\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m--user\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 17\u001b[0m help\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miLO username to login\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 18\u001b[0m default\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'argparse' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # Initialize parser \n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\") \n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ " #stroing namespace object in options\n",
+ " options = parser.parse_args()\n",
+ " #getting namespaceobject ilo_ip address\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " #printing the url obtain by ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " \n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " reset_server(redfish_obj)\n",
+ " else:\n",
+ " reset_server_gen9(redfish_obj)\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/server_manager/set_server_asset_tag.ipynb b/example_jupyter_notebooks/server_manager/set_server_asset_tag.ipynb
new file mode 100644
index 0000000..63499d0
--- /dev/null
+++ b/example_jupyter_notebooks/server_manager/set_server_asset_tag.ipynb
@@ -0,0 +1,238 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "c3169c50",
+ "metadata": {},
+ "source": [
+ "
Setting server asset tag
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "70635f68",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting server asset tag. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f176e2a7",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cbe979de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616c5812",
+ "metadata": {},
+ "source": [
+ "
2. This is our set_server_asset_tag function overview.
\n",
+ "
\n",
+ "1. The
set_server_asset_tag function sets the server asset tag on an iLO device. The function takes two parameters: _redfishobj and tag. \n",
+ "
\n",
+ " - _redfishobj is a Redfish client object that represents the connection to the server
\n",
+ " - tag is a string that represents the asset tag to be set for the server.
\n",
+ "
\n",
+ "2. In the
set_server_asset_tag function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.
\n",
+ "3. In the ILO rest api the information about server asset tag is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the server asset tag of iLO system.
\n",
+ "4. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "5. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #ComputerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.
\n",
+ "6.The function then calls the
patch() method to update the system's AssetTag property with the new tag provided as input to the function.
\n",
+ "7. If the iLO device responds with a status code outside of 200 or 201, the function attempts to access the iLO extended message info to see what went wrong.
\n",
+ "8. If the patch() operation is successful, the updated asset tag is printed to the console. The function then waits for 10 seconds before retrieving and displaying the updated asset tag.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f4e166b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_server_asset_tag(_redfishobj, tag):\n",
+ "\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response and systems_members_uri and tag:\n",
+ " print(\"Current Asset Tag: \\'%s\\'\\n\" % systems_members_response.dict.get(\"AssetTag\"))\n",
+ "\n",
+ " resp = _redfishobj.patch(systems_members_uri, {\"AssetTag\" : tag})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " time.sleep(10) #going to wait 10 seconds before obtaining the LED indicator state\n",
+ " sys.stdout.write(\"\\nUpdated Asset Tag: \\'%s\\'\\n\" % _redfishobj.\\\n",
+ " get(systems_members_uri).dict.get(\"AssetTag\"))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ef4f1fb5",
+ "metadata": {},
+ "source": [
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to set_server_asset_tag to set server asset tag of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bf946980",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "606190a9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #asset tag property in computer systems\n",
+ " ASSET_TAG = \"Asset01\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_server_asset_tag(REDFISHOBJ, ASSET_TAG)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63db964c",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/server_manager/set_uid_light.ipynb b/example_jupyter_notebooks/server_manager/set_uid_light.ipynb
new file mode 100644
index 0000000..8de099b
--- /dev/null
+++ b/example_jupyter_notebooks/server_manager/set_uid_light.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "8ce5d6a0",
+ "metadata": {},
+ "source": [
+ "
Setting the UID light
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b76e816",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Setting UID light\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to set uid light. This code is written in Python and uses the redfish library to perform the required operations.
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0581e350",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1875796e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1eb087ac",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is our set_uid_light to function overview, in the end this will set uid light.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "1. This is a function that uses the Redfish API to toggle the UID (Universal Identification) LED on a computer system.\n",
+ " The function takes a Redfish connection object
_redfishobj as its only argument.
\n",
+ "2. In the
set_uid_light function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ "3. In the iLO rest api the information about UID light is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the UID light settings of iLO system.\n",
+ "
\n",
+ "4. In the system members response object with different
odata_id we get a system uri . Then again an http GET request is made and response is stored in
system_response. Then we set the
system_members_uri.
\n",
+ "5. Else if resource directory is enabled then we will simply iterate through all instances inside resources and if #ComputerSystem attribute is present in @odata.type attribute then we'll set system_members_uri and get system_members_response settings of the user through redfish object.
\n",
+ "6.It sets the body[\"IndicatorLED\"] key to Lit if the current value of the IndicatorLED property is Off, or to \"Off\" otherwise.
\n",
+ "7. It sends an HTTP PATCH request to the obtained URI with the body payload to update the IndicatorLED property.
\n",
+ "8. If the response status code is not 200 (OK) or 201 (Created), it prints an error message and exits.
\n",
+ "9. If the response status code is 200 or 201, it waits for 10 seconds to allow the firmware to update the LED status, and then sends a GET request to the same URI to obtain the updated resource representation of the computer system.
\n",
+ "10. It prints the updated value of the IndicatorLED property.
\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "07276165",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_uid_light(_redfishobj):\n",
+ "\n",
+ " body = dict()\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response and systems_members_uri:\n",
+ " print(\"Current Indicator LED Status: \\'%s\\'\\n\" % systems_members_response.dict.\\\n",
+ " get(\"IndicatorLED\"))\n",
+ " if \"Off\" in systems_members_response.dict.get(\"IndicatorLED\"):\n",
+ " print(\"Will illuminate indicator LED.\\n\")\n",
+ " body[\"IndicatorLED\"] = \"Lit\"\n",
+ " else:\n",
+ " print(\"Will extinguish indicator LED.\\n\")\n",
+ " body[\"IndicatorLED\"] = \"Off\"\n",
+ "\n",
+ " resp = _redfishobj.patch(systems_members_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " time.sleep(10) #going to wait 10 seconds before obtaining the LED indicator state\n",
+ " sys.stdout.write(\"\\nUpdated Indicator LED Status: \\'%s\\'\\n\" % _redfishobj.\\\n",
+ " get(systems_members_uri).dict['IndicatorLED'])\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "70d73b57",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "
\n",
+ " \n",
+ "2. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call set_uid_light with our redfish object to set UID light.
\n",
+ "
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3e4a9804",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea7ed17c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_uid_light(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "377dc76a",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/smartarray_storage/get_SmartArray_EncryptionSettings.ipynb b/example_jupyter_notebooks/smartarray_storage/get_SmartArray_EncryptionSettings.ipynb
new file mode 100644
index 0000000..effd715
--- /dev/null
+++ b/example_jupyter_notebooks/smartarray_storage/get_SmartArray_EncryptionSettings.ipynb
@@ -0,0 +1,229 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "24f88e8b",
+ "metadata": {},
+ "source": [
+ "
Smart Array Encryption Settings On HPE ILO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91296f4e",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98f640a8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c954abda",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e8336308",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is about gathering the smart array encryption settings on HPE iLO systems
\n",
+ " \n",
+ "1. The function get_SmartArray_EncryptionSettings retrieves encryption settings for Smart Storage Array Controllers from a Redfish service.
\n",
+ "
\n",
+ " \n",
+ "2.It first checks if the resource directory is disabled or empty, and if so, it navigates through the Redfish service object to obtain the necessary URIs for Smart Storage Array Controllers
\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is enabled and not empty, the function uses the resource directory to find the relevant URI for Smart Storage Array Controllers.
\n",
+ "
\n",
+ "\n",
+ "4. It retrieves detailed information about each Smart Storage Array Controller and stores it in the smartarraycontrollers dictionary using the controller's @odata.id as the key.
\n",
+ "
\n",
+ "5. The function prints the encryption properties for each Smart Storage Array Controller, specifically the properties listed in the desired_properties list.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e85045dc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_SmartArray_EncryptionSettings(_redfishobj, desired_properties):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " smart_storage_uri = systems_members_response.obj.Oem.Hpe.Links['SmartStorage']['@odata.id']\n",
+ " smart_storage_arraycontrollers_uri = _redfishobj.get(smart_storage_uri).obj.Links['ArrayControllers']['@odata.id']\n",
+ " smartstorage_response = _redfishobj.get(smart_storage_arraycontrollers_uri).obj['Members']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeSmartStorageArrayControllerCollection.' in instance['@odata.type']:\n",
+ " smartstorage_uri = instance['@odata.id']\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ " break\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Encryption Properties for Smart Storage Array Controller \\'%s\\' : \\n% smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " for data in smartarraycontrollers[controller['@odata.id']]:\n",
+ " if data in desired_properties:\n",
+ " sys.stdout.write(\"\\t %s : %s\\n\" % (data, smartarraycontrollers[controller]['@odata.id']].get(data)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c776e47a",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2e71e12a",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "05fc8da8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ " #list of desired properties related to Smart Array controller encryption\n",
+ " DESIRED_PROPERTIES = [\"Name\", \"Model\", \"SerialNumber\", \"EncryptionBootPasswordSet\",\"EncryptionCryptoOfficerPasswordSet\",\"EncryptionLocalKeyCacheEnabled\", \"EncryptionMixedVolumesEnabled\",\"EncryptionPhysicalDriveCount\", \"EncryptionRecoveryParamsSet\",\"EncryptionStandaloneModeEnabled\", \"EncryptionUserPasswordSet\"]\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_SmartArray_EncryptionSettings(REDFISHOBJ, DESIRED_PROPERTIES)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "123c6927",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/smartarray_storage/get_logical_drives.ipynb b/example_jupyter_notebooks/smartarray_storage/get_logical_drives.ipynb
new file mode 100644
index 0000000..2a78035
--- /dev/null
+++ b/example_jupyter_notebooks/smartarray_storage/get_logical_drives.ipynb
@@ -0,0 +1,306 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "594a0e06",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
get_logical-drives. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25be0e98",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
argparse\n",
+ "
get_resource_directory\n",
+ "
get_gen\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f16a98ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c2b4d45",
+ "metadata": {},
+ "source": [
+ "
2.
This is our get_SmartArray_LogicalDrives function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present for error free execution.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "1. The variables smartstorage_response and smartarraycontrollers are initialized as an empty list and dictionary, respectively.\n",
+ "
\n",
+ "\n",
+ "2. The get_resource_directory function is used in the code to try and retrieve the resource directory. The code resorts to a manual search for the pertinent URIs if the resource directory is unavailable or the DISABLE_RESOURCE_DIR flag is set to True.The code repeats the preceding code snippet's procedures to retrieve the pertinent URIs for smart storage and array controllers if the resource directory is not in use or unavailable.\n",
+ "
\n",
+ "\n",
+ "3. The code searches through each instance in the resource directory for instances of the specified type if the resource directory is used. It fetches the response, which is an array of array controller members, and extracts the instance's URI. After locating the first pertinent instance, the loop ends.\n",
+ "The smartstorage_response is then used by the code, presuming it contains the array of array controller elements.\n",
+ "The code obtains specific information about each controller in smartstorage_response and stores it in the smartarraycontrollers dictionary with the controller's @odata.id as the key.\n",
+ "
\n",
+ " \n",
+ "4.For the specified smart storage array controller, it prints the logical drive URIs.The code gets the logical drives URI from the controller's links, sends an HTTP GET request to get the answer, and sets the result to the logicaldrives_resp variable. \n",
+ "
\n",
+ " \n",
+ "5.The LogicalDrives key in the smartarraycontrollers dictionary is used to add the logical drive members.\n",
+ "A message is sent to stderr if there are no logical drives.\n",
+ "
\n",
+ " \n",
+ "6.The code publishes information about each logical drive in logicaldrives_resp, fetches detailed drive data with an HTTP GET request, and prints the drive data as JSON.\n",
+ "
\n",
+ " \n",
+ "7. The initial values of the variables smartarraycontrollers and smartstorage_response are a dictionary and an empty \n",
+ "list respectively.The code configures the smartstorage_uri to point to the endpoint \n",
+ "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/ for Gen9 servers. To obtain data about the array\n",
+ "controllers, use this endpoint.\n",
+ "
\n",
+ "\n",
+ "8. An HTTP GET request is sent to the smartstorage_uri, and the array of array controller members is extracted \n",
+ "from the response to populate the smartstorage_response.The code obtains specific information about each controller \n",
+ "in smartstorage_response and stores it in the smartarraycontrollers dictionary with the controller\n",
+ "@odata.id as the key.\n",
+ "
\n",
+ "9.The logical drive URIs for the specific smart storage array controller are printed by the code.The controller links, \n",
+ "specifically the LogicalDrives key under the Links object, are where the logicaldrives_uri is located.In order to \n",
+ "receive the logical drives response, which provides details about the logical drives connected to the controller, \n",
+ "the code performs an HTTP GET request to the logicaldrives_uri.\n",
+ "
\n",
+ "10.If the number of logical drive members is zero, an error message stating that no logical \n",
+ "drives are accessible for this controller is sent to stderr.Otherwise, the code publishes information about each \n",
+ "logical drive in the logicaldrives_resp, makes an HTTP GET request to the logical drive URI ,obtains detailed drive \n",
+ "data, and prints the drive data as JSON.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "95b318b7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_SmartArray_LogicalDrives_gen9(_redfishobj):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " smartstorage_uri = \"/redfish/v1/Systems/1/SmartStorage/ArrayControllers/\"\n",
+ " print (smartstorage_uri)\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Logical Drive URIs for Smart Storage Array Controller \\'%s\\' : \\n\" \\\n",
+ " % smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " logicaldrives_uri = smartarraycontrollers[controller['@odata.id']].Links\\\n",
+ " ['LogicalDrives']['@odata.id']\n",
+ " print (logicaldrives_uri)\n",
+ " logicaldrives_resp = _redfishobj.get(logicaldrives_uri)\n",
+ " if logicaldrives_resp.dict['Members@odata.count'] == 0:\n",
+ " sys.stderr.write(\"\\tLogical drives are not available for this controller.\\n\")\n",
+ " else:\n",
+ " for lds in logicaldrives_resp.dict['Members']:\n",
+ " sys.stdout.write(\"\\t An associated logical drive: %s\\n\" % logicaldrives_resp.dict['Name'])\n",
+ " drive_data = _redfishobj.get(lds['@odata.id']).dict\n",
+ " print(json.dumps(drive_data, indent=4, sort_keys=True))\n",
+ "def get_SmartArray_LogicalDrives_gen9(_redfishobj):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " smartstorage_uri = \"/redfish/v1/Systems/1/SmartStorage/ArrayControllers/\"\n",
+ " print (smartstorage_uri)\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Logical Drive URIs for Smart Storage Array Controller \\'%s\\' : \\n\" \\\n",
+ " % smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " logicaldrives_uri = smartarraycontrollers[controller['@odata.id']].Links\\\n",
+ " ['LogicalDrives']['@odata.id']\n",
+ " print (logicaldrives_uri)\n",
+ " logicaldrives_resp = _redfishobj.get(logicaldrives_uri)\n",
+ " if logicaldrives_resp.dict['Members@odata.count'] == 0:\n",
+ " sys.stderr.write(\"\\tLogical drives are not available for this controller.\\n\")\n",
+ " else:\n",
+ " for lds in logicaldrives_resp.dict['Members']:\n",
+ " sys.stdout.write(\"\\t An associated logical drive: %s\\n\" % logicaldrives_resp.dict['Name'])\n",
+ " drive_data = _redfishobj.get(lds['@odata.id']).dict\n",
+ " print(json.dumps(drive_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b852d783",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: \n",
+ "
\n",
+ " - An instance of the argparse is created by the code.assigns the ArgumentParser class to the parser variable. The goal of the script is described in the description parameter.
\n",
+ " - Using the add_argument method of the ArgumentParser class, the code adds the following three command-line arguments:1.-i or --ilo: Specifies the iLO IP address of the server
2.u or --user: Indicates the iLO login username. It has the dest, action, help, and default parameters, just as the -i argument.
\n",
+ " 3.-p or --password: Specifies the iLO password for login.\n",
+ " \n",
+ " - A new variable named system_url is created and given the value \"https://\" + options.ilo_ip by the code. This creates the system's URL using the supplied iLO IP address. The iLO IP address will come after the \"https://\" in the final URL.The created URL will be shown on the console once the code outputs the system_url variable.
\n",
+ " - The DISABLE_RESOURCE_DIR option is set to False by the code. This option is used to specify whether or not the resource directory should be disabled, along with any related procedures. It is specifically set to False in this instance, allowing the resource directory to be utilised.
\n",
+ " - The base_url, username, and password that were received through the command-line inputs are passed to the code, which then creates a RedfishClient object with the name redfish_obj.The specified credentials are used to log in to the server by calling the redfish_obj.login() method. A session is established with the server as a result.A ServerDownOrUnreachableError exception is thrown if the server cannot be reached or does not support Redfish, and the script is terminated after printing an error message to stderr.
\n",
+ " - The redfish_obj is supplied as an argument when the get_gen() function is used. The server generation data is retrieved using this function.The second value of the tuple given by get_gen() is disregarded using , and the server generation is kept in the ilogen variable.The console is printed with the server generation.
\n",
+ " - The get_SmartArray_LogicalDrives() function is called with the redfish_obj parameter to obtain details on the smart array logical drives if the server generation is equal to 5, indicating a Gen5 server.\n",
+ "The get_SmartArray_LogicalDrives_gen9() function is called with the redfish_obj parameter to obtain details about the smart array logical drives unique to Gen9 servers if the server generation is not 5, indicating a different generation.
\n",
+ " - Finally logout from the session can be done by using redfish_obj.logout()
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "610979dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " get_SmartArray_LogicalDrives(redfish_obj)\n",
+ " else:\n",
+ " get_SmartArray_LogicalDrives_gen9(redfish_obj)\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80f7da07",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b5c8a5",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/smartarray_storage/test.txt b/example_jupyter_notebooks/smartarray_storage/test.txt
new file mode 100644
index 0000000..e69de29
diff --git a/example_jupyter_notebooks/snmp/configure_snmp.ipynb b/example_jupyter_notebooks/snmp/configure_snmp.ipynb
new file mode 100644
index 0000000..2676691
--- /dev/null
+++ b/example_jupyter_notebooks/snmp/configure_snmp.ipynb
@@ -0,0 +1,237 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "979defcc",
+ "metadata": {},
+ "source": [
+ "
Configuring SNMP for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Welcome to
python-iLOrest-library This is an example of
configuring SNMP for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "824911d8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory \n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "
2. This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alerts):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related information of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d5fe2f86",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " ALERTS_ENABLED = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_ENABLED, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/snmp/configure_snmp_trap_source.ipynb b/example_jupyter_notebooks/snmp/configure_snmp_trap_source.ipynb
new file mode 100644
index 0000000..0b15ed6
--- /dev/null
+++ b/example_jupyter_notebooks/snmp/configure_snmp_trap_source.ipynb
@@ -0,0 +1,226 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0a6c95aa",
+ "metadata": {},
+ "source": [
+ "
Configuring SNMP trap source for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "594a0e06",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "Welcome to
python-iLOrest-library This is an example of
configuring SNMP trap source for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25be0e98",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "125ad9ac",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c2b4d45",
+ "metadata": {},
+ "source": [
+ "
2. This is our configure_snmp function overview, in the end this will give us with snmp service related information.
\n",
+ " \n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the snmp service information.\n",
+ "\n",
+ " \n",
+ "\n",
+ " \n",
+ "1. In the ILO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "2. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if power snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b53e8e73",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ " def configure_snmp(_redfishobj):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " # print(managers_members_response.obj['Oem']['Hpe']['Links'])\n",
+ " # exit(0)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['SNMPService']['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " # resp = _redfishobj.get(snmp_service_uri)\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " # exit(0)\n",
+ " # TrapSourceHostname : Manager or System\n",
+ " body = {\"TrapSourceHostname\": \"System\"}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b852d783",
+ "metadata": {},
+ "source": [
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related info of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80f7da07",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "610979dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " if len(sys.argv) <= 3:\n",
+ " sys.stderr.write(\"ERROR: We need 3 arguments. \\nUsage: change-snmp.py \"\n",
+ " \"ILOIPADDR ILOUSER ILOPASSWORD \\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " SYSTEM_URL = \"https://\" + sys.argv[1]\n",
+ " LOGIN_ACCOUNT = sys.argv[2]\n",
+ " LOGIN_PASSWORD = sys.argv[3]\n",
+ "\n",
+ " try:\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,\n",
+ " password=LOGIN_PASSWORD)\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b5c8a5",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/snmp/set_snmp_alert.ipynb b/example_jupyter_notebooks/snmp/set_snmp_alert.ipynb
new file mode 100644
index 0000000..cea51c3
--- /dev/null
+++ b/example_jupyter_notebooks/snmp/set_snmp_alert.ipynb
@@ -0,0 +1,315 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "80ca2bf5",
+ "metadata": {},
+ "source": [
+ "
Setting SNMP alert destination
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "647c7374",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting SNMP alert destination. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ce2b4b70",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e6a53c06",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfd0ef73",
+ "metadata": {},
+ "source": [
+ "
2. This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "269747d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alertdestinations, DISABLE_RESOURCE_DIR):\n",
+ " snmp_service_uri = None\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " #body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " body = {\"AlertDestinations\": snmp_alertdestinations}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ca33ee48",
+ "metadata": {},
+ "source": [
+ "
3. This is our set_snmp_alert_destination function overview.
\n",
+ "
\n",
+ "1. The
set_snmp_alert_destination function sets the SNMP alert destinations on an iLO device. The function takes three parameters: _redfishobj, snmp_service_uri, and alert_destination_list. \n",
+ "
\n",
+ " - _redfishobj is the Redfish client object.
\n",
+ " - snmp_service_uri is the URI for the SNMP service on the iLO device.
\n",
+ " - alert_destination_list is a list of dictionaries containing the SNMP alert destinations to set.
\n",
+ "
\n",
+ "2. The function gets the current SNMP service data using
_redfishobj.get() and checks if the
AlertDestinations property is available/modifyable.
\n",
+ "3. If the property is available/modifyable, the function sends a PATCH request with the updated alert destinations using
_redfishobj.patch().
\n",
+ "4. If the iLO device responds with a status code outside of 200 or 201, the function attempts to access the iLO extended message info to see what went wrong.
\n",
+ "5. If the patch operation is successful, the function prints the response and gets the updated SNMP alert destination data using
_redfishobj.get().
\n",
+ "6. The updated SNMP alert destination data is printed to the console using
json.dumps() and
print().
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c91c0fb8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_snmp_alert_destination(_redfishobj, snmp_service_uri, alert_destination_list):\n",
+ " data = _redfishobj.get(snmp_service_uri)\n",
+ " if data.dict.get(\"AlertDestinations\"):\n",
+ " resp = _redfishobj.patch(snmp_service_uri, {'AlertDestinations': alert_destination_list})\n",
+ " else:\n",
+ " raise Exception(\"\\'AlertDestinations\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nPatch operation successful!\\n\\nResponse:\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " snmp_service_response = _redfishobj.get(snmp_service_uri).dict.get('AlertDestinations')\n",
+ " print(\"\\n\\nPrinting updated SNMP alert destination:\\n\")\n",
+ " print(json.dumps(snmp_service_response, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9fdd0d40",
+ "metadata": {},
+ "source": [
+ "
4. This is Main function overview.
\n",
+ "
The Main function \n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - It checks the generation of iLO by calling the get_gen function and prints the iLO generation.\n",
+ "
- If the iLO generation is 5, it calls the configure_snmp function to configure the SNMP service with the read communities and alerts destination, and disable resource directory flag.
\n",
+ "- If the iLO generation is not 5, it calls the set_snmp_alert_destination function to set the SNMP alert destination with the alert destination list for iLO4.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a2f6ba5",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27378983",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " #SYSTEM_URL = \"https://15.146.46.45\"\n",
+ " #LOGIN_ACCOUNT = \"admin\"\n",
+ " #LOGIN_PASSWORD = \"admin123\"\n",
+ "\n",
+ " SYSTEM_URL = sys.argv[1]\n",
+ " LOGIN_ACCOUNT = sys.argv[2]\n",
+ " LOGIN_PASSWORD = sys.argv[3]\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " #ALERTS_ENABLED = True\n",
+ " #Alert Destination\n",
+ " ALERTS_DESTINATION = [\"1.1.1.1\",\"2.2.2.2\"]\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ " snmp_service_uri = \"/redfish/v1/Managers/1/SNMPService/\"\n",
+ "\n",
+ " # Number of max alert destination supported on iLO4 and iLO5 is different\n",
+ " alert_destination_list = [\"ILOCN771702NJ\", \"15.146.46.55\" , \"15.146.46.58\"]\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " (ilogen,_) = get_gen(REDFISHOBJ)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_DESTINATION, DISABLE_RESOURCE_DIR)\n",
+ " else:\n",
+ " set_snmp_alert_destination(REDFISHOBJ, snmp_service_uri, alert_destination_list)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28ec396f",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/users_and_sessions/account_remove.ipynb b/example_jupyter_notebooks/users_and_sessions/account_remove.ipynb
new file mode 100644
index 0000000..7907409
--- /dev/null
+++ b/example_jupyter_notebooks/users_and_sessions/account_remove.ipynb
@@ -0,0 +1,250 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Remove iLO User Account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
a particular user account on HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ "
In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ " for proper execution of our code.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of removing a user account from the HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
\n",
+ " Below is the remove_ilo_user_account function, after sucessful execution of this function we will be able to delete the information of any user account that is present on the HPE iLO system.\n",
+ " \n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " \n",
+ "For removal of any general account from the system we will first have to search for the accounts that we wan't to delete based on any attribute or property that uniquely identifies the account. Upon finding that account we can just make http delete request and we are done!\n",
+ " \n",
+ "1. In the
remove_ilo_user_account function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
In case the resource directory was disabled we are navigating to the actual location where the all the member account information is stored by using
DELETErequest.\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources to obtain the
account_collection_uri.\n",
+ "
\n",
+ "4.
\n",
+ " - Now we are having the location at which all the member accounts are present.
- Simply we just find out what user account matches the account that has to be deleted based on username of the accounts.
- If we do not find the required account after completion of iteration we print out a message that required acccount was not found on the server side.
\n",
+ " - After this we simply make a DELETE request to delete that particular account and save the response obtained in resp variable.
If the http status code returned was 200, then we simply print a message that delete operation was success.
\n",
+ " Else if the status code returned was anything else we print out the status code with an error message to get idea about what went wrong.\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def remove_ilo_user_account(_redfishobj, username_to_delete):\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " #find the account to delete\n",
+ " account_uri_to_delete = None\n",
+ " #collection of account URIs located at the account_collection_uri endpoint using the HTTP GET method\n",
+ " account_uris = _redfishobj.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " # retrieving the account object located at the URI specified by account_uri['@odata.id'] using \n",
+ " #the HTTP GET method\n",
+ " account = _redfishobj.get(account_uri['@odata.id'])\n",
+ " #checking whether username is matching with the username_to_delete\n",
+ " if account.dict['UserName'] == username_to_delete:\n",
+ " account_uri_to_delete = account_uri['@odata.id']\n",
+ " break\n",
+ " #deleting a resource located at the account_uri_to_delete endpoint \n",
+ " if not account_uri_to_delete:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ " #deleting account found in the account_uri_to_delete\n",
+ " resp = _redfishobj.delete(account_uri_to_delete)\n",
+ " #checking the status for post request\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ "
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - The ACCOUNT_TO_DELETE contains the username of the account that we need to delete. We are passing the same as an argument while making a call to remove_ilo_user_account function.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to remove_ilo_user_account function .
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ " \n",
+ " \n",
+ " # The username of the account to remove\n",
+ " ACCOUNT_TO_DELETE = \"joker\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " #calling function \n",
+ " remove_ilo_user_account(REDFISHOBJ, ACCOUNT_TO_DELETE)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/example_jupyter_notebooks/users_and_sessions/add_user_account.ipynb b/example_jupyter_notebooks/users_and_sessions/add_user_account.ipynb
new file mode 100644
index 0000000..84a87c0
--- /dev/null
+++ b/example_jupyter_notebooks/users_and_sessions/add_user_account.ipynb
@@ -0,0 +1,507 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "
Add new user account by iLO privileges or redfish standard roles
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "613446a1",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is our add_ilo_user_account function overview, in the end this will add new iLO user account. This function will be called only if the generation of iLO is not 4.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new iLO user account.
\n",
+ "\n",
+ "1. This function takes in six parameters: _redfishobj, new_loginname, new_username, new_password, role_id, and privilege_dict.\n",
+ "
\n",
+ " \n",
+ "2. The function first calls the get_resource_directory() function by passing _redfishobj as the parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, the function obtains all the account instances from the resource directory and sets the account_collection_uri. If it's an HPE server, it sets the body dictionary with the privileges passed in privilege_dict parameter.\n",
+ "
\n",
+ "\n",
+ "4. The function then fills the body dictionary with the necessary details like new_username, new_password, and RoleId/Oem depending on the type of server.\n",
+ "
\n",
+ "\n",
+ "5. The function then sends a POST command by passing the account_collection_uri and body dictionary as the parameters to create a new user account.\n",
+ "
\n",
+ "\n",
+ "6. If the iLO server responds with an HTTP status code outside of 200 or 201, the function prints an error message. If the HTTP response status code is 400, it prints the iLO extended info error message. If the HTTP response status code is 200 or 201, it prints a success message and the newly created user account details in JSON format.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea197a20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account(_redfishobj, new_loginname, new_username, new_password, role_id, privilege_dict):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #Add via role id\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " #HPE server, so add via privileges\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " #Add login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " #Fill in the rest of the payload\n",
+ " body[\"UserName\"] = new_username\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "94f279a6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
This function adds a new iLO user account in the HPE Gen9 server or having iLO generation 4 servers.
\n",
+ " \n",
+ " \n",
+ "1. The function takes _redfishobj, new_loginname, new_username, and new_password as input parameters..\n",
+ "
\n",
+ " \n",
+ "2. The account collection URI for the HPE Gen9 server is initialized as /redfish/v1/AccountService/Accounts/.\n",
+ "
\n",
+ "\n",
+ "3. The privilege dictionary for the HPE Gen9 server is constructed in the body variable. The privileges are specified for the iLO user account to be added. The login name is also added.\n",
+ "
\n",
+ "\n",
+ "4. The username and password for the iLO user account to be added are added to the body dictionary.\n",
+ "
\n",
+ "\n",
+ "5. The POST command is passed to _redfishobj to add the iLO user account using the account_collection_uri and body dictionary.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is 200 or 201, the newly created user account details are printed using json.dumps().\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If the HTTP response status code is not 200 or 201, an error message is printed using sys.stderr.write().\n",
+ " \n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bc44c03c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account_gen9(_redfishobj, new_loginname, new_username, new_password):\n",
+ "\n",
+ " account_collection_uri = \"/redfish/v1/AccountService/Accounts/\"\n",
+ " #Add via gen9 priv dic\n",
+ " body = {'Oem': {'Hp': {'Privileges': {\"LoginPriv\": True, \"RemoteConsolePriv\": True,\n",
+ " \"UserConfigPriv\": True, \"VirtualMediaPriv\": True, \"VirtualPowerAndResetPriv\": True,\n",
+ " \"iLOConfigPriv\": True}, 'LoginName': new_loginname}},'UserName': new_username, 'Password': new_password}\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new user.\n",
+ " \n",
+ "\n",
+ " 1. The follwoing Main function prompts to take SYSTEM_URL, LOGIN_ACCOUNT, LOGIN_PASSWORD, ACCOUNT_LOGIN_NAME, ACCOUNT_USER_NAME, ACCOUNT_PASSWORD, ROLE_ID and PRIVILAGES as inputs.
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " 2. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ " 3. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object. If users want to use create RedfishClient using \"certificate\" for authentication (which is optional), they can do so by uncommenting the lines ca_cert_data, ca_cert_data, ca_cert_data,ca_cert_data and providing their values.
\n",
+ "
\n",
+ " \n",
+ " 4. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ " \n",
+ " 5. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " 6. Then we call add_ilo_user_account or add_ilo_user_account_gen9 based on the generation of iLO by pssing appropriate as parameters to those functions.
\n",
+ " \n",
+ " \n",
+ " 7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally, use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39d4c0f0",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Roles and Privileges
\n",
+ "
iLO uses a set of privileges assigned to each user account to grant and restrict access to features. iLO 6’s privileges are:
\n",
+ " \n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Redfish | \n",
+ " iLO Web Interface (GUI) | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv | \n",
+ " Login | \n",
+ "
\n",
+ " \n",
+ " | RemoteConsolePriv | \n",
+ " Remote Console | \n",
+ "
\n",
+ " \n",
+ " | VirtualPowerAndResetPriv | \n",
+ " Virtual Power and Reset | \n",
+ "
\n",
+ " \n",
+ " | VirtualMediaPriv | \n",
+ " Virtual Media | \n",
+ "
\n",
+ " \n",
+ " | HostBIOSConfigPriv | \n",
+ " Host BIOS | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv | \n",
+ " Configure iLO Settings | \n",
+ "
\n",
+ " \n",
+ " | UserConfigPriv | \n",
+ " Administer User Accounts | \n",
+ "
\n",
+ " \n",
+ " | HostNICConfigPriv | \n",
+ " Host NIC | \n",
+ "
\n",
+ " \n",
+ " | HostStorageConfigPriv | \n",
+ " Host Storage | \n",
+ "
\n",
+ " \n",
+ " | SystemRecoveryConfigPriv | \n",
+ " Recovery Set | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
Roles
\n",
+ "
You can use RoleId to create users with specific starting privileges.
\n",
+ "On a GET of the local user account, RoleId is synthesized based upon the enabled privileges. iLO 6 does not store a separate RoleId value. For this reason, modifications to raw privileges may or may not result in a changed RoleId based upon iLO’s mapping.
\n",
+ "If the PATCH includes both RoleID and individual privileges, the privileges corresponding to the RoleId are assigned to the local user account first, and then the explicit privileges are assigned.
\n",
+ "\n",
+ "
Privileges granted on Local Account Creation by RoleId
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | RoleId | \n",
+ " Privileges | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Administrator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, UserConfigPriv, VirtualMediaPriv, VirtualPowerAndResetPriv, iLOConfigPriv | \n",
+ "
\n",
+ " \n",
+ " | Operator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, VirtualMediaPriv, VirtualPowerAndResetPriv | \n",
+ "
\n",
+ " \n",
+ " | ReadOnly | \n",
+ " LoginPriv | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "
RoleId shown on an existing Local User Account by Privilege
\n",
+ "
The RoleId reported is the smallest superset of assigned privileges.
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Privileges | \n",
+ " RoleId | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv only | \n",
+ " ReadOnly | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv or UserConfigPriv or SystemRecoveryConfigPriv and anything else | \n",
+ " Administrator | \n",
+ "
\n",
+ " \n",
+ " | any other combination | \n",
+ " Operator | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ " \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b99181a4",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #account login name (iLO GUI actually considers this to be 'UserName', but\n",
+ " #this is the redfish standard username)\n",
+ " ACCOUNT_LOGIN_NAME = input(\"Enter Account Login Name: \")\n",
+ "\n",
+ " #account user name (iLO GUI actually considers this to be 'LoginName', but\n",
+ " #this is the redfish login)\n",
+ " ACCOUNT_USER_NAME = input(\"Enter Account User Name: \")\n",
+ "\n",
+ " #account password\n",
+ " ACCOUNT_PASSWORD = getpass.getpass(\"Enter Account password: \")\n",
+ "\n",
+ " #A predefined role for the user, (The redfish standard method for accounts).\n",
+ " #This is a translated to a pre-configured arrangement of privileges on HPE servers\n",
+ " ROLE_ID = input(\"Enter ROLE_ID: \") #Administrator, ReadOnly or Operator are available\n",
+ "\n",
+ " #Dictionary of modifiable privileges for HPE servers (modify this if you wish to directly set\n",
+ " #an account with specific privileges\n",
+ " \n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": True, \"VirtualMediaPriv\": True, \"RemoteConsolePriv\": True, \"UserConfigPriv\": True, \"VirtualPowerAndResetPriv\": True, \\\n",
+ " \"SystemRecoveryConfigPriv\": True, \"LoginPriv\": True, \"HostStorageConfigPriv\": True, \"HostNICConfigPriv\": True,\n",
+ " \"HostBIOSConfigPriv\": True}\n",
+ " \n",
+ " print(\"For the below privilages enter 'True' if that privilages needs to be set for the user else enter 'False'\")\n",
+ " \n",
+ " for key in PRIVILEGE_DICT.keys():\n",
+ " PRIVILEGE_DICT[key] = input(f\"{key}\")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ "# ca_cert_data = {}\n",
+ "# ca_cert_data[\"cert_file\"] = \"c:\\\\test\\\\ppcacuser.crt\"\n",
+ "# ca_cert_data[\"key_file\"] = \"c:\\\\test\\\\ppcacuserpriv.key\"\n",
+ "# ca_cert_data[\"key_password\"] = \"password\"\n",
+ " LOGIN_ACCOUNT = None\n",
+ " LOGIN_PASSWORD = None\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD, ca_cert_data=ca_cert_data)\n",
+ " #REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, ca_cert_data=ca_cert_data)\n",
+ " # Login with the Redfish client\n",
+ " if ca_cert_data is None:\n",
+ " REDFISHOBJ.login()\n",
+ " else:\n",
+ " REDFISHOBJ.login(auth='certificate')\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ "\n",
+ " #if account_collection_uri and accounts:\n",
+ " #add specified account\n",
+ " (ilogen,_) = get_gen(REDFISHOBJ)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) !=4:\n",
+ " add_ilo_user_account(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD,ROLE_ID,PRIVILEGE_DICT)\n",
+ " else:\n",
+ " add_ilo_user_account_gen9(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD)\n",
+ " \n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acf871b9",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/users_and_sessions/modify_user_account.ipynb b/example_jupyter_notebooks/users_and_sessions/modify_user_account.ipynb
new file mode 100644
index 0000000..f16ab22
--- /dev/null
+++ b/example_jupyter_notebooks/users_and_sessions/modify_user_account.ipynb
@@ -0,0 +1,326 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22cbd656",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "#modify_user_account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is a example
modify_user_account. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ccd0447f",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "
2.
This is our modify_ilo_user_account function overview, in the end this will help you to modify the account.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings..\n",
+ "\n",
+ "1. In the modify_user_account function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. Retrieves the account service URI, sends a GET request to the account service, and obtains the account collection URI. If a role_id is provided, it creates a request body with the modified RoleId parameter.\n",
+ "
\n",
+ " \n",
+ "3. Else Iterate over resource instances to find the account collection URI. Modify privileges and/or login name if specified for an HPE server.\n",
+ "
\n",
+ " \n",
+ "4. If new User name is there then modified the new user name and password in the body.\n",
+ " Iterate over account URIs to find the one with a matching username. If found, modify the account using a PATCH request to the identified URI.\n",
+ "
\n",
+ " \n",
+ "5.Handling the error after inserting the iso image in slot \n",
+ "If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ "If status code is 200 OK then it will print error meassage and status code.\n",
+ "Else the modification is success then code print result in JSON format.\n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "def modify_ilo_user_account(_redfishobj, username_to_modify, new_loginname, new_username, \\\n",
+ " new_password, role_id, privilege_dict):\n",
+ "\n",
+ " account_collection_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #modify role id\n",
+ " if role_id:\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " if privilege_dict:\n",
+ " #HPE server, so modify privileges\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " if new_loginname:\n",
+ " #modify login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " if new_username:\n",
+ " body[\"UserName\"] = new_username\n",
+ " if new_password:\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #find the account to modify\n",
+ " account_uri_to_modify = None\n",
+ " account_uris = REDFISHOBJ.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = REDFISHOBJ.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_modify:\n",
+ " account_uri_to_modify = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_modify:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " #modify the account by sending patch request\n",
+ " resp = REDFISHOBJ.patch(account_uri_to_modify, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER BASED WHERE YOU ARE RUUNIG THE SERVER
\n",
+ "
\n",
+ " - The variables USERNAME_TO_MODIFY, NEW_LOGINNAME, NEW_USERNAME, NEW_PASSWORD, and ROLE_ID have been assigned with the specified values.
\n",
+ " - PRIVILEGE_DICT represents a dictionary where each key corresponds to a specific privilege and the corresponding value indicates whether that privilege is enabled or disabled.
\n",
+ " - Using the redfish object we are trying to establish the connection with the server.After establish the connection we try to login .If the server is unreachable we noftify the user with error message.
\n",
+ " - If login is successful then we are calling the function with proper parameter.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "faa032c5",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 43\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 42\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 43\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 44\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 45\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 47\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 46\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 47\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 48\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 49\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #username of the account to modify\n",
+ " USERNAME_TO_MODIFY = \"bruce_wayne\"\n",
+ "\n",
+ " #account login name to change the account to\n",
+ " NEW_LOGINNAME = \"joker\"\n",
+ "\n",
+ " #account user name to change the account to\n",
+ " NEW_USERNAME = \"joker\"\n",
+ "\n",
+ " #account password to change the account to\n",
+ " NEW_PASSWORD = \"joker123\"\n",
+ "\n",
+ " #role to change account to\n",
+ " ROLE_ID = \"ReadOnly\" #Administrator, ReadOnly or Operator are available\n",
+ "\n",
+ " #update HPE account privileges\n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": False, \"VirtualMediaPriv\": False, \"RemoteConsolePriv\": True,\\\n",
+ " \"UserConfigPriv\": False, \"VirtualPowerAndResetPriv\": False, \\\n",
+ " \"SystemRecoveryConfigPriv\": False, \"LoginPriv\": True, \\\n",
+ " \"HostStorageConfigPriv\": False, \"HostNICConfigPriv\": False, \\\n",
+ " \"HostBIOSConfigPriv\": False}\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " modify_ilo_user_account(REDFISHOBJ, USERNAME_TO_MODIFY, NEW_LOGINNAME, NEW_USERNAME, \\\n",
+ " NEW_PASSWORD, ROLE_ID, PRIVILEGE_DICT)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/users_and_sessions/sessions.ipynb b/example_jupyter_notebooks/users_and_sessions/sessions.ipynb
new file mode 100644
index 0000000..fc1f0bb
--- /dev/null
+++ b/example_jupyter_notebooks/users_and_sessions/sessions.ipynb
@@ -0,0 +1,252 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "
Manually Managing Sessions With Redfish
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
manually managing sessions with Redfish As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from six.moves import urllib\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is about sessions function
\n",
+ " \n",
+ "1. This function creates a new session with an iLO server using provided login credentials..
\n",
+ "
\n",
+ " \n",
+ "2. The function sends a POST request to the /redfish/v1/Sessions endpoint to create the session..
\n",
+ "
\n",
+ "\n",
+ "3. If the session is created successfully (response code 201), the function prints the session URI and X-Auth Token key..
\n",
+ "
\n",
+ "\n",
+ "4. The function also sends a DELETE request to the session URI to terminate the session.
\n",
+ "
\n",
+ "5. If the session creation fails, the function prints an error message and tries to access the iLO Extended Message Info for more details..
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def sessions(_redfishobj, login_account, login_password):\n",
+ "\n",
+ " new_session = {\"UserName\": login_account, \"Password\": login_password}\n",
+ " response = _redfishobj.post('/redfish/v1/Sessions', new_session)\n",
+ "\n",
+ " if response.status == 201:\n",
+ " print(\"Success!\\n\")\n",
+ " session_uri = response.getheader(\"location\")\n",
+ " session_uri = urllib.parse.urlparse(session_uri)\n",
+ " sys.stdout.write(\"\\tSession \" + session_uri.path + \" created.\\n\")\n",
+ " x_auth_token = response.getheader(\"x-auth-token\")\n",
+ " sys.stdout.write(\"\\tThis is the session X-Auth Token key \" + x_auth_token + \".\\n\")\n",
+ " print(json.dumps(response.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " # Delete the created session\n",
+ " sys.stdout.write(\"\\tTerminating this session.\\n\")\n",
+ " sessresp = _redfishobj.delete(session_uri.path)\n",
+ " print(json.dumps(sessresp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"ERROR: failed to create a session.\\n\")\n",
+ " try:\n",
+ " print(json.dumps(sessresp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended\"\n",
+ " \" Message Info...\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " sessions(REDFISHOBJ, LOGIN_ACCOUNT, LOGIN_PASSWORD)#calling sessions function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "316c3f0e",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/virtual_media/eject_virtual_media_iso.ipynb b/example_jupyter_notebooks/virtual_media/eject_virtual_media_iso.ipynb
new file mode 100644
index 0000000..9556027
--- /dev/null
+++ b/example_jupyter_notebooks/virtual_media/eject_virtual_media_iso.ipynb
@@ -0,0 +1,263 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
mounting virtual media for HPE iLO systems As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Below we are importing all the necessary modules from the ilorest library! To know more about the modules click below\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "
2.
This is our mount_virtual_media_iso function overview, in the end this will give us with virtual media related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the virtual media information.\n",
+ "\n",
+ "1. In the
mount_virtual_media_iso function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about virtual media is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the virtual media about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The virtual media information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if virtual media is present in
@odata.type attribute then we will store information about virtual media in virtual_media_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if virtual_media_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, media_type,):\n",
+ "\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.EjectMedia']['target']\n",
+ " post_body = {\"Action\": \"HpeiLOVirtualMedia.EjectVirtualMedia\"}\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 25\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 26\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 27\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 31\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 30\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 31\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 32\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 33\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " \n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = \"CD\" #current possible options: Floppy, USBStick, CD, DVD\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ "\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_TYPE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90621a8a",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/example_jupyter_notebooks/virtual_media/mount_virtual_media_iso.ipynb b/example_jupyter_notebooks/virtual_media/mount_virtual_media_iso.ipynb
new file mode 100644
index 0000000..cfa0710
--- /dev/null
+++ b/example_jupyter_notebooks/virtual_media/mount_virtual_media_iso.ipynb
@@ -0,0 +1,322 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "266e8885",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Mount_virtual-media_iso"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "358b08b4",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
mount_virtual_media_iso As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "578dfc4d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c82681e9",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/1390777471.py\u001b[0m in \u001b[0;36m
\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "84274de2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our mount_virtual-media_iso function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present.
\n",
+ "\n",
+ "1. In the change_bios_settings function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. Retrieving information on the server's management interfaces using the Redfish API client, including members and their properties and retrieving URI for virtual media using Redfish API client.\n",
+ "
\n",
+ "\n",
+ "3. Else Using the Redfish API client and the Resource Directory, iterating through resource instances, and obtaining the URI for the virtual media collection.\n",
+ "
\n",
+ "4. If virtual_media_uri is not None then If a slot matches, the program fetches the URI for adding media into that slot and then sends a POST request to the supplied URL to insert the ISO image. Additionally, the code sends a PATCH request to set the option if a parameter is provided for the server to restart from the virtual media.\n",
+ "
\n",
+ "\n",
+ "5. Handling the error after inserting the iso image in slot \n",
+ " If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ " If status code is 200 OK then it will print error meassage and status code.\n",
+ " Else the insertion is success then code print result in JSON format.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "cc680e58",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, iso_url, media_type, boot_on_next_server_reset):\n",
+ " #Initializing variables for virtual media API responses.\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "#Retrieving resource directory instances using Redfish API client.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " #retriving information Virtual media using redfish object and specified parameter\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " #iterates through each virtual media to find proper slot\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.InsertMedia']['target']\n",
+ " post_body = {\"Image\": iso_url}\n",
+ "\n",
+ " if iso_url:\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if boot_on_next_server_reset is not None:\n",
+ " patch_body = {}\n",
+ " patch_body[\"Oem\"] = {\"Hpe\": {\"BootOnNextServerReset\": \\\n",
+ " boot_on_next_server_reset}}\n",
+ " boot_resp = _redfishobj.patch(data.obj['@odata.id'], patch_body)\n",
+ " if not boot_resp.status == 200:\n",
+ " sys.stderr.write(\"Failure setting BootOnNextServerReset\")\n",
+ " #handling error after inserting iso image in slot \n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "567eb3f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "
\n",
+ "1. If server is runnig in locally then url,login_account,Login-password will be None.\n",
+ " Else then we need to enter the proper credential.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "2. media_url will provide access and mount the iso image in server side and we initial media_type to CD.
\n",
+ "
\n",
+ "\n",
+ "3. Utilising the Redfish API to create a Redfish client object with the provided login information and log in to the server.
\n",
+ "
\n",
+ "\n",
+ "4. resolving the exception that is thrown when the server cannot be reached or does not implement the Redfish API, printing a message of error to standard error output, and terminating the program
\n",
+ "
\n",
+ "5. Using the Redfish API client object and the given arguments to mount a virtual media ISO image on a server.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "7c01d222",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Enter System URL: 120.1.114.51\n",
+ "Enter Name: tann\n",
+ "Enter password: none\n",
+ "Enter bios password: noen\n",
+ "Enter bios property you wish to change: yes\n",
+ "Enter Value of the property to change: none\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 17\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 16\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 17\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 19\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 21\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 20\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 21\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 22\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 23\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ " # used to access and mount iso image on server side\n",
+ " MEDIA_URL = \"http:///media.iso\"\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = \"CD\" #current possible options: Floppy, USBStick, CD, DVD\n",
+ " #specify if the server should attempt to boot this media on system restart\n",
+ " BOOT_ON_NEXT_SERVER_RESET = True\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_URL, MEDIA_TYPE, BOOT_ON_NEXT_SERVER_RESET)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9d0181a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9e9f0846",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks.zip b/examples/Jupyter_notebooks.zip
new file mode 100644
index 0000000..996cc66
Binary files /dev/null and b/examples/Jupyter_notebooks.zip differ
diff --git a/examples/Jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb b/examples/Jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb
new file mode 100644
index 0000000..58031df
--- /dev/null
+++ b/examples/Jupyter_notebooks/.ipynb_checkpoints/index-checkpoint.ipynb
@@ -0,0 +1,53 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "453f77bb-9a66-492a-bf03-a737b524a484",
+ "metadata": {},
+ "source": [
+ "|OPERATION|DESCRIPTION| METHOD | LOCATION |\n",
+ "|-------------|--------------------------------------|-------------------------|------------------------|\n",
+ "|bios settings|update bios settings for iLO server| PATCH |[change_bios_setting](examples/change_bios_settings.ipynb)|\n",
+ "|bios default| update bios to default setting | PATCH |[revert_bios_default](examples/bios_revert_default.ipynb)|\n",
+ "|powermetrics average|get powewr measurement average of servers| GET |[get_powermetrics_average](examples/get_powermetrics_average.ipynb)|\n",
+ "|change boot order|update the existing boot order or add new order| PUT |[change_boot_order](examples/change_bios_settings.ipynb)|\n",
+ "|change temporary boot order|update or reset an temporary boot order| PUT |[change_temporary_boot_order](examples/change_bios_settings.ipynb)|\n",
+ "|clear ahs data | clear active health state data of iLO server| DELETE |[clear_ahs_data](examples/clear_ahs_data.ipynb)|\n",
+ "|computer details|get all the available computer/hosts details in iLO| GET |[computer_details](examples/computer_details.ipynb)|\n",
+ "|expand data|expand the response data obtained from any of the http methods| GET |[expand_data](examples/change_bios_settings.ipynb)\n",
+ "|generate_csr|obtain a certificate signing request for iLO server | GET |[generate_csr](examples/generate_csr.ipynb)|\n",
+ "|get ahs info|obtain active health status data of the iLO servers| GET |[get_ahs_data](examples/get_ahs_data.ipynb)|\n",
+ "|base message registry|get base message registry info of iLO servers| GET |[get_base_registry](examples/change_bios_settings.ipynb)|\n",
+ "|iLO ip address|obtain the ip address of iLO servers| GET |[get_ilo_ip](examples/get_ilo_ip.ipynb)|\n",
+ "|License key|get iLO license key for iLO| GET |[get_license_key](examples/get_license_key.ipynb)|\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "974fdedd-2bb1-4a4c-adb5-a6052e134085",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/eject_virtual_media_iso-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/eject_virtual_media_iso-checkpoint.ipynb
new file mode 100644
index 0000000..484ef38
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/eject_virtual_media_iso-checkpoint.ipynb
@@ -0,0 +1,281 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "71861904",
+ "metadata": {},
+ "source": [
+ "Mount Virtual Media ISO
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.This is our mount_virtual_media_iso function overview, in the end this will give us with virtual media related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the virtual media information.\n",
+ "\n",
+ "1. In the
mount_virtual_media_iso function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about virtual media is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the virtual media about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The virtual media information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if virtual media is present in
@odata.type attribute then we will store information about virtual media in virtual_media_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if virtual_media_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, media_type,):\n",
+ "\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.EjectMedia']['target']\n",
+ " post_body = {\"Action\": \"HpeiLOVirtualMedia.EjectVirtualMedia\"}\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90621a8a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 25\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 26\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 27\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 31\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 30\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 31\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 32\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 33\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " \n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = \"CD\" #current possible options: Floppy, USBStick, CD, DVD\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ "\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_TYPE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "722783e3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enable_secure_boot--checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enable_secure_boot--checkpoint.ipynb
new file mode 100644
index 0000000..81c755a
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enable_secure_boot--checkpoint.ipynb
@@ -0,0 +1,271 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0e4729be",
+ "metadata": {},
+ "source": [
+ "Enable Secure Boot
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b44c9aad",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
enabling secure boot As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "74ee46a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3b9ca27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0e073c6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.This is our enable_secure_boot function overview, in the end this will give us with secure boot related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the secure boot information.\n",
+ "\n",
+ "1. In the
enable_secure_boot function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about secureboot is stored inside the
systems json object.\n",
+ " Through systems_response variable we are making a http
GET operation to and trying to obtain the secure boot about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the systems response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
systems_members_response.\n",
+ " The secure boot information is ultimately present in the
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if secure boot is present in
@odata.type attribute then we will store information about secure boot in secure_boot_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if secure_boot_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8d60549e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_secure_boot(_redfishobj, secure_boot_enable):\n",
+ "\n",
+ " secure_boot_uri = None\n",
+ " secure_boot_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " secure_boot_uri = systems_members_response.obj['SecureBoot']['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#SecureBoot.' in instance['@odata.type']:\n",
+ " secure_boot_uri = instance['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ "\n",
+ " if secure_boot_data:\n",
+ " print(\"\\n\\nShowing Secure Boot properties before changes:\\n\\n\")\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if secure_boot_uri:\n",
+ " body = {'SecureBootEnable': secure_boot_enable}\n",
+ " resp = _redfishobj.patch(secure_boot_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\n\\nShowing Secure Boot properties after changes:\\n\\n\")\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b227f8f6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
Please enter your login credentials here to proceed further:
\n",
+ "
\n",
+ " - Once your credentials are entered, a Redfish object is created with the help of the RedfishClient class, and a session is created to log you in to the server.
\n",
+ " - If the server is down or unreachable, we get a \"server not reachable\" message.
\n",
+ " - If not, we make a call to the enable_secure_boot function to obtain secure boot-related information of the system.
\n",
+ " - After getting the required information, Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28cb201c",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8028b4ff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #secure boot enable property\n",
+ " SECURE_BOOT_ENABLE = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_secure_boot(REDFISHOBJ, SECURE_BOOT_ENABLE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf8a164b",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "31a7ae05",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enabling_ntp_server-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enabling_ntp_server-checkpoint.ipynb
new file mode 100644
index 0000000..9714f29
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/enabling_ntp_server-checkpoint.ipynb
@@ -0,0 +1,313 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Enable Ntp Servers
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
enable ntp servers . As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.Below function describes the process how to enable NTP servers for HPE ilo systems. NTP or Network Time Protocol is an internet protocol used to synchronize with computer clokc time sources in a network. \n",
+ "Current cell is the explains the processes performed inside the below function.
\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. Initially, to obtain NTP server related information for HPE ilo systems a series of HTTP GET requests are being made so as to navigate to that path inside the iLO rest api where required information is stored.\n",
+ "After completion of these get requests we will be having the relevant uri in
manager_ethernet_interfaces_members.\n",
+ "
\n",
+ "2. Else if
resource directory is enabled we can just use the resource directory to and then again navigate through the api to find relevant uri.\n",
+ "
\n",
+ " \n",
+ "3. Whatever changes need to be made to enable the NTP server are being enclosed inside the dictionary named as
body. Next up for all the instances of ethernet in ethernet_data we simply make a
HTTP PATCH request by passing the ethernet instance and body dictionary with the PATCH request. \n",
+ " \n",
+ "\n",
+ "4. Following the patch request, the response returned by server is being saved inside resp variable and later if the server returns proper response it means there is no error else error is returned with error information. A reference for json.dumps\n",
+ "function as it is used multiple times -
click here.\n",
+ "\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_ntp(_redfishobj, ntp_servers, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " print(json.dumps(ethernet_data, indent=4, sort_keys=True))\n",
+ "\n",
+ " body = {\"Oem\": {\"Hpe\": {\"DHCPv4\": {\"UseNTPServers\": ntp_servers}, \\\n",
+ " \"DHCPv6\": {\"UseNTPServers\": ntp_servers}}}}\n",
+ " for ethernet in ethernet_data:\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " _data = _redfishobj.get(ethernet).dict\n",
+ " sys.stdout.write(\"\\nShowing \\'%s\\' interface after changes:\\n\" % ethernet)\n",
+ " print(json.dumps(_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to enable_ntp function by passing parameters such as redfishclient object and enable flag to perform required operation.
\n",
+ "- After getting required information Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'ilorest'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mgetpass\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m redfish_client\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mredfish_object\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m RedfishClient\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mexceptions\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ServerDownOrUnreachableError\n",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'ilorest'"
+ ]
+ }
+ ],
+ "source": [
+ "import getpass\n",
+ "from ilorest import redfish_client\n",
+ "from ilorest.redfish_object import RedfishClient\n",
+ "from ilorest.exceptions import ServerDownOrUnreachableError\n",
+ "\n",
+ "def main():\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n",
+ "if __name__ == \"__main__\":\n",
+ " main()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/generate_csr-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/generate_csr-checkpoint.ipynb
new file mode 100644
index 0000000..4ada111
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/generate_csr-checkpoint.ipynb
@@ -0,0 +1,283 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "042acf39",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Generating a certificate signing request for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b34599c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
generate_csr!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7338dfb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0c9837f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "034daf66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our generate csr function overview, in the end we will be able to make a certificate signing request.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
generate_csr function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about Http certificates is stored inside the
managers json object.\n",
+ " And now through managers_response variable, we are making a http
GET operation to and trying to obtain the certificates of signing of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system managers members response object with different
odata_id we get a security service uri .\n",
+ " Then again an http GET request is made and response is stored in
security_service_response.\n",
+ " Then we will make a http_cert_response by using csr_uri through security_service_response and then using http_cert_response we will get
generate_csr_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeHttpsCert attribute is present in
@odata.type attribute then we'll set csr_uri and
get generate csr uri of the target.\n",
+ "
\n",
+ "\n",
+ "5. If
generate_csr_uri exists, then we will define the body and send a
post request through redfish object. After generating the csr, we can obtain the
csr_response using
get method for csr_uri.
csr_response contains
CertificateSigningRequest. \n",
+ "\n",
+ "
\n",
+ "6. If you get the result, then it is successful. if you don't get the result, then there is an error.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "644bd708",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_csr(_redfishobj, csr_file, csr_properties):\n",
+ "\n",
+ " csr_uri = None\n",
+ " generate_csr_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " csr_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " https_cert_response = _redfishobj.get(csr_uri)\n",
+ " generate_csr_uri = https_cert_response.obj['Actions']['#HpeHttpsCert.GenerateCSR']\\\n",
+ " ['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " csr_uri = instance['@odata.id']\n",
+ " generate_csr_uri = _redfishobj.get(csr_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " break\n",
+ "\n",
+ " if generate_csr_uri:\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.GenerateCSR\"\n",
+ " body[\"City\"] = csr_properties[\"City\"]\n",
+ " body[\"CommonName\"] = csr_properties[\"CommonName\"]\n",
+ " body[\"Country\"] = csr_properties[\"Country\"]\n",
+ " body[\"OrgName\"] = csr_properties[\"OrgName\"]\n",
+ " body[\"OrgUnit\"] = csr_properties[\"OrgUnit\"]\n",
+ " body[\"State\"] = csr_properties[\"State\"]\n",
+ " resp = _redfishobj.post(generate_csr_uri, body)\n",
+ " if resp.status in [200, 201]:\n",
+ " sys.stdout.write(\"Generating CSR, this may take a few minutes\\n\")\n",
+ " sys.stdout.write(\"Sleeping for 5 minutes...\\n\")\n",
+ " time.sleep(600)\n",
+ " csr_resp = _redfishobj.get(csr_uri).dict['CertificateSigningRequest']\n",
+ " with open(csr_file, 'wb') as csroutput:\n",
+ " csroutput.write(csr_resp)\n",
+ " sys.stdout.write(\"CSR Data saved to file: '%s'\\n\" % csr_file)\n",
+ " else:\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status not in [200, 201]:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2da11ba0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter your ilo url,Username,Password here.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call generate_csr with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06934cbc",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46b3e899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #CSR Dictionary, each value should be updated to reflect the desired CSR\n",
+ " CSR_DICT = {\"City\" : input(\"Enter city:\"), \"CommonName\": input(\"Enter name:\"), \"Country\": input(\"Enter country :\"), \\\n",
+ " \"OrgName\": input(\"Enter organization :\"), \"OrgUnit\": input(\"Enter unit :\"), \"State\": input(\"Enter state:\")}\n",
+ "\n",
+ " #After CSR is generated, a file will be created and the CSR will be downloaded\n",
+ " CSR_FILE = \"csr.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " generate_csr(REDFISHOBJ, CSR_FILE, CSR_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12c33902",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/sessions-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/sessions-checkpoint.ipynb
new file mode 100644
index 0000000..beef720
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/sessions-checkpoint.ipynb
@@ -0,0 +1,250 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ " Manually Managing Sessions With Redfish
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
manually managing sessions with Redfish As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from six.moves import urllib\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about sessions function
\n",
+ " \n",
+ "1. This function creates a new session with an iLO server using provided login credentials..
\n",
+ "
\n",
+ " \n",
+ "2. The function sends a POST request to the /redfish/v1/Sessions endpoint to create the session..
\n",
+ "
\n",
+ "\n",
+ "3. If the session is created successfully (response code 201), the function prints the session URI and X-Auth Token key..
\n",
+ "
\n",
+ "\n",
+ "4. The function also sends a DELETE request to the session URI to terminate the session.
\n",
+ "
\n",
+ "5. If the session creation fails, the function prints an error message and tries to access the iLO Extended Message Info for more details..
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def sessions(_redfishobj, login_account, login_password):\n",
+ "\n",
+ " new_session = {\"UserName\": login_account, \"Password\": login_password}\n",
+ " response = _redfishobj.post('/redfish/v1/Sessions', new_session)\n",
+ "\n",
+ " if response.status == 201:\n",
+ " print(\"Success!\\n\")\n",
+ " session_uri = response.getheader(\"location\")\n",
+ " session_uri = urllib.parse.urlparse(session_uri)\n",
+ " sys.stdout.write(\"\\tSession \" + session_uri.path + \" created.\\n\")\n",
+ " x_auth_token = response.getheader(\"x-auth-token\")\n",
+ " sys.stdout.write(\"\\tThis is the session X-Auth Token key \" + x_auth_token + \".\\n\")\n",
+ " print(json.dumps(response.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " # Delete the created session\n",
+ " sys.stdout.write(\"\\tTerminating this session.\\n\")\n",
+ " sessresp = _redfishobj.delete(session_uri.path)\n",
+ " print(json.dumps(sessresp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"ERROR: failed to create a session.\\n\")\n",
+ " try:\n",
+ " print(json.dumps(sessresp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended\"\n",
+ " \" Message Info...\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ " Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.\n",
+ " If server is down or Unreachable we get server not reachable message!\n",
+ " If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.\n",
+ " After getting required information Redfish.logout() closses the particular session and logs us out of the system.\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " sessions(REDFISHOBJ, LOGIN_ACCOUNT, LOGIN_PASSWORD)#calling sessions function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "316c3f0e",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_PrimaryKeyServer-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_PrimaryKeyServer-checkpoint.ipynb
new file mode 100644
index 0000000..b4709f2
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_PrimaryKeyServer-checkpoint.ipynb
@@ -0,0 +1,297 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Set_ESKM_PrimaryKeyServer
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
set_ESKM_PrimaryKeyServer As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about set_ESKM_PrimaryKeyServer function
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "1. This function sets the primary key server for the HPE ESKM service.
\n",
+ "
\n",
+ " \n",
+ "2. It takes three arguments: _redfishobj (an object representing the Redfish service), primary_key_server_address (a string representing the IP address or hostname of the primary key server), and primary_key_server_port (an integer representing the port number of the primary key server).
\n",
+ "
\n",
+ "\n",
+ "3. It uses the get_resource_directory function to find the relevant ESKM URI, which is used to make a POST request to set the primary key server.
\n",
+ "
\n",
+ "\n",
+ "4. If the POST request is successful (returns an HTTP status code of 200), the function prints a success message and the JSON response from the server.
\n",
+ "
\n",
+ "5. If the POST request is unsuccessful, the function prints an error message and, if available, the extended error information from the server response.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ESKM_PrimaryKeyServer(_redfishobj, primary_key_server_address, primary_key_server_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ "\n",
+ " body[\"PrimaryKeyServerAddress\"] = primary_key_server_address\n",
+ " body[\"PrimaryKeyServerPort\"] = int(primary_key_server_port)\n",
+ "\n",
+ " resp = _redfishobj.post(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " PRIMARY_KEY_SERVER_ADDRESS = \"192.168.1.1\"\n",
+ " PRIMARY_KEY_SERVER_PORT = \"9000\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ESKM_PrimaryKeyServer(REDFISHOBJ, PRIMARY_KEY_SERVER_ADDRESS, PRIMARY_KEY_SERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_username_password-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_username_password-checkpoint.ipynb
new file mode 100644
index 0000000..d650f16
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/.ipynb_checkpoints/set_ESKM_username_password-checkpoint.ipynb
@@ -0,0 +1,290 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Setting the ESKM username and password for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
setting the ESKM username and password for HPE iLO systems As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about ESKM_username_pass function
\n",
+ " \n",
+ "1. The function sets up an Electronic Software Key Manager (ESKM) on an iLO (Integrated Lights Out) server using the Redfish API.
\n",
+ "
\n",
+ " \n",
+ "2. It takes several input parameters including ESKM username, password, account group, primary key server address, and primary key server port.
\n",
+ "
\n",
+ "\n",
+ "3. It first attempts to locate the URI for the ESKM resource either by using the Redfish Resource Directory or by manually navigating through the Redfish API.br>\n",
+ "
\n",
+ "\n",
+ "4. If the ESKM URI is found, the function constructs a JSON payload containing the ESKM configuration information and primary key server details and sends it as a PATCH request to the ESKM resource.
\n",
+ "
\n",
+ "5. If the PATCH request is successful (i.e., returns an HTTP status code of 200), the function prints out a success message along with the response payload, otherwise it prints out an error message.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ESKM_username_pass(_redfishobj, eskm_username, eskm_password, eskm_accountgroup, \\\n",
+ " eskm_primarykeyserver_addr, eskm_primarykeyserver_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " body[\"KeyManagerConfig\"] = dict()\n",
+ " body[\"KeyManagerConfig\"][\"LoginName\"] = eskm_username\n",
+ " body[\"KeyManagerConfig\"][\"Password\"] = eskm_password\n",
+ " body[\"KeyManagerConfig\"][\"AccountGroup\"] = eskm_accountgroup\n",
+ " body[\"KeyManagerConfig\"][\"ESKMLocalCACertificateName\"] = \"\"\n",
+ " body[\"PrimaryKeyServerAddress\"] = eskm_primarykeyserver_addr\n",
+ " body[\"PrimaryKeyServerPort\"] = eskm_primarykeyserver_port\n",
+ " resp = _redfishobj.patch(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " ESKM_USERNAME = \"admin\"\n",
+ " ESKM_PASSWORD = \"password\"\n",
+ " ESKM_ACCOUNTGROUP = \"group\"\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR = \"192.168.1.10\"\n",
+ " ESKM_PRIMARYKEYSERVER_PORT = 5927\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " ESKM_username_pass(REDFISHOBJ, ESKM_USERNAME, ESKM_PASSWORD, ESKM_ACCOUNTGROUP, \\\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR, ESKM_PRIMARYKEYSERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enable_secure_boot-.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enable_secure_boot-.ipynb
new file mode 100644
index 0000000..aa30d83
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enable_secure_boot-.ipynb
@@ -0,0 +1,255 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0e4729be",
+ "metadata": {},
+ "source": [
+ "Enable Secure Boot
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b44c9aad",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "74ee46a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3b9ca27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0e073c6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.This is our enable_secure_boot function overview, in the end this will give us with secure boot related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the secure boot information.\n",
+ "\n",
+ "1. In the
enable_secure_boot function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about secureboot is stored inside the
systems json object.\n",
+ " Through systems_response variable we are making a http
GET operation to and trying to obtain the secure boot about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the systems response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
systems_members_response.\n",
+ " The secure boot information is ultimately present in the
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if secure boot is present in
@odata.type attribute then we will store information about secure boot in secure_boot_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if secure_boot_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8d60549e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_secure_boot(_redfishobj, secure_boot_enable):\n",
+ "\n",
+ " secure_boot_uri = None\n",
+ " secure_boot_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " secure_boot_uri = systems_members_response.obj['SecureBoot']['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#SecureBoot.' in instance['@odata.type']:\n",
+ " secure_boot_uri = instance['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ "\n",
+ " if secure_boot_data:\n",
+ " print(\"\\n\\nShowing Secure Boot properties before changes:\\n\\n\")\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if secure_boot_uri:\n",
+ " body = {'SecureBootEnable': secure_boot_enable}\n",
+ " resp = _redfishobj.patch(secure_boot_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\n\\nShowing Secure Boot properties after changes:\\n\\n\")\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b227f8f6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
Please enter your login credentials here to proceed further:
\n",
+ "
\n",
+ " - Once your credentials are entered, a Redfish object is created with the help of the RedfishClient class, and a session is created to log you in to the server.
\n",
+ " - If the server is down or unreachable, we get a \"server not reachable\" message.
\n",
+ " - If not, we make a call to the enable_secure_boot function to obtain secure boot-related information of the system.
\n",
+ " - After getting the required information, Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28cb201c",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8028b4ff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #secure boot enable property\n",
+ " SECURE_BOOT_ENABLE = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_secure_boot(REDFISHOBJ, SECURE_BOOT_ENABLE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf8a164b",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enabling_ntp_server.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enabling_ntp_server.ipynb
new file mode 100644
index 0000000..3e062ce
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/enabling_ntp_server.ipynb
@@ -0,0 +1,307 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Enable Ntp Servers
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.Below function describes the process how to enable NTP servers for HPE ilo systems. NTP or Network Time Protocol is an internet protocol used to synchronize with computer clokc time sources in a network. \n",
+ "Current cell is the explains the processes performed inside the below function.
\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. Initially, to obtain NTP server related information for HPE ilo systems a series of HTTP GET requests are being made so as to navigate to that path inside the iLO rest api where required information is stored.\n",
+ "After completion of these get requests we will be having the relevant uri in
manager_ethernet_interfaces_members.\n",
+ "
\n",
+ "2. Else if
resource directory is enabled we can just use the resource directory to and then again navigate through the api to find relevant uri.\n",
+ "
\n",
+ " \n",
+ "3. Whatever changes need to be made to enable the NTP server are being enclosed inside the dictionary named as
body. Next up for all the instances of ethernet in ethernet_data we simply make a
HTTP PATCH request by passing the ethernet instance and body dictionary with the PATCH request. \n",
+ " \n",
+ "\n",
+ "4. Following the patch request, the response returned by server is being saved inside resp variable and later if the server returns proper response it means there is no error else error is returned with error information. A reference for json.dumps\n",
+ "function as it is used multiple times -
click here.\n",
+ "\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_ntp(_redfishobj, ntp_servers, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']['@odata.id']\n",
+ " \n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.obj['Members']\n",
+ " \n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in instance['@odata.id']:\n",
+ " \n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.get(_ethernet_interface['@odata.id']).dict\n",
+ " \n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " print(json.dumps(ethernet_data, indent=4, sort_keys=True))\n",
+ "\n",
+ " body = {\"Oem\": {\"Hpe\": {\"DHCPv4\": {\"UseNTPServers\": ntp_servers},\"DHCPv6\": {\"UseNTPServers\": ntp_servers}}}}\n",
+ " \n",
+ " for ethernet in ethernet_data:\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,sort_keys=True))\n",
+ " \n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " \n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " _data = _redfishobj.get(ethernet).dict\n",
+ " sys.stdout.write(\"\\nShowing \\'%s\\' interface after changes:\\n\" % ethernet)\n",
+ " print(json.dumps(_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to enable_ntp function by passing parameters such as redfishclient object and enable flag to perform required operation.
\n",
+ "- After getting required information Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'ilorest'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mgetpass\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m redfish_client\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mredfish_object\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m RedfishClient\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01milorest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mexceptions\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ServerDownOrUnreachableError\n",
+ "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'ilorest'"
+ ]
+ }
+ ],
+ "source": [
+ "import getpass\n",
+ "from ilorest import redfish_client\n",
+ "from ilorest.redfish_object import RedfishClient\n",
+ "from ilorest.exceptions import ServerDownOrUnreachableError\n",
+ "\n",
+ "def main():\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n",
+ "if __name__ == \"__main__\":\n",
+ " main()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/find_ilo_mac_address.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/find_ilo_mac_address.ipynb
new file mode 100644
index 0000000..b7a7604
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/find_ilo_mac_address.ipynb
@@ -0,0 +1,224 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Find ilo Mac Address
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17541bb6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.This is our find_ilo_mac_address function overview, in the end this will give us about finding ilo mac address related information.
\n",
+ "
Let me give you a walk through of it!
\n",
+ "
\n",
+ " - For the identification of a device, its mac address is very much required. If you have the Systems Management Homepage installed, you can find out by clicking \"Management Processor\" and then check the Physical Address field.
\n",
+ " - If we don't have a resource directory, information about the ethernet data is stored inside the managers json object. Through managers_response variable we are making a http GET operation to and trying to obtain the virtual media about iLO system.
\n",
+ " - Ethernet interface gives the response for that member about the ilo mac address
\n",
+ " - If the resource directory is present, then we will simply iterate through all instances inside resources and if the ethernet interface is present in @odata.type attribute then we will store information about ethernet interface in ethernet_data dictionary and break out of iteration.
\n",
+ " - Finally, we get iLo Network Manager Interface and iLO Mac Address as output.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_ilo_mac_address(_redfishobj):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces'] ['@odata.id']\n",
+ " \n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.obj['Members']\n",
+ " \n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in instance['@odata.id']:\n",
+ " \n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.get(_ethernet_interface['@odata.id']).dict\n",
+ " \n",
+ " for iface in ethernet_data:\n",
+ " sys.stdout.write(\"iLO Network Manager Interface: \\'%s\\'\\n\" % ethernet_data[iface]['Id'])\n",
+ " sys.stdout.write(\"\\tiLO Mac Address: \\'%s\\'\\n\" % ethernet_data[iface].get('MACAddress'))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get \"server not reachable\" message!
\n",
+ " - and Once everything is done you are automatically logged out with .logout()
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " find_ilo_mac_address(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/flash_firmware_by_uefi.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/flash_firmware_by_uefi.ipynb
new file mode 100644
index 0000000..6887534
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/flash_firmware_by_uefi.ipynb
@@ -0,0 +1,397 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Uploading Firmware to the iLO Repository For Flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from random import randint\n",
+ "\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "import logging\n",
+ "from redfish import redfish_logger\n",
+ "\n",
+ "from ilorest_util import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "102138e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "LOGGERFILE = \"RedfishApiExamples.log\"\n",
+ "LOGGERFORMAT = \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n",
+ "LOGGER = redfish_logger(LOGGERFILE, LOGGERFORMAT, logging.DEBUG)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about upload_firmware function
\n",
+ " \n",
+ "1. The function upload_firmware takes in parameters such as _redfishobj, firmware_loc, comp_type, update_repo, and update_target..
\n",
+ "
\n",
+ " \n",
+ "2. It uploads firmware to a specified location using the Redfish API and HTTP POST request.
\n",
+ "
\n",
+ "\n",
+ "3. The function first obtains the UpdateService URI and HttpPushUri using the _redfishobj and then reads the firmware file as binary data.
\n",
+ "
\n",
+ "\n",
+ "4. It creates a payload containing the session key, JSON data, and the firmware file in multipart-form data format..
\n",
+ "
\n",
+ "5. Finally, the function sends the payload as an HTTP POST request to the specified path and returns an appropriate response based on the HTTP status code.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, comp_type, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " print (update_service_uri)\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ " print (path)\n",
+ "\n",
+ " body = []\n",
+ "\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " #ImageLocation = \"c:\\\\test\"\n",
+ " #filename = \"I41_2.40_08_10_2020.fwpkg\"\n",
+ " #ImagePath = os.path.join(ImageLocation, filename)\n",
+ " #file_name = os.path.basename(firmware_loc)\n",
+ " #print (ImagePath)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(file_tuple)\n",
+ " #print (body)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " print ('Begin upload....please wait...')\n",
+ " # We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2b320019",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is about create task function
\n",
+ " \n",
+ "1. The function create_task takes in parameters such as _redfishobj, firmware_loc, and tpm_flag.
\n",
+ "
\n",
+ " \n",
+ "2. It creates a new task for applying firmware updates using the Redfish API and HTTP POST request.
\n",
+ "
\n",
+ "\n",
+ "3. The function first obtains the session key and creates the necessary header dictionary for the HTTP request.It then checks if there are any current tasks in the task queue before creating a new task with a random ID and the given firmware file name.
\n",
+ "
\n",
+ "\n",
+ "4. The task is created using the update_task dictionary and sent as an HTTP POST request to the specified path.
\n",
+ "
\n",
+ "5. Finally, the function returns an appropriate response based on the HTTP status code.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bcac4f85",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - The path to the firmware file to upload (-c/--component)
\n",
+ " - The iLO IP of the server (-i/--ilo)
\n",
+ " - The iLO username to login (-u/--user)
\n",
+ " - The iLO password to log in (-p/--password)
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09f2bc6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def create_task(_redfishobj, firmware_loc, tpm_flag=True):\n",
+ "\n",
+ " session_key = _redfishobj.session_key\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " updatable_by = ['Uefi']\n",
+ " task_path = '/redfish/v1/UpdateService/UpdateTaskQueue/'\n",
+ " file_name = os.path.basename(firmware_loc)\n",
+ "\n",
+ " task_resp = _redfishobj.get(task_path)\n",
+ " if not task_resp.obj[\"Members@odata.count\"]:\n",
+ " print (\"No current tasks, proceed to create new task\")\n",
+ "\n",
+ "\n",
+ " update_task = {'Name': 'Update-%s-%s' % (str(randint(0, 1000000)),file_name), 'Command': 'ApplyUpdate','Filename': file_name, 'UpdatableBy': updatable_by, 'TPMOverride': tpm_flag}\n",
+ "\n",
+ " resp = _redfishobj.post(task_path, update_task, headers=header)\n",
+ " #print (resp)\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to create update task queue...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Task Queue Creation complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-c',\n",
+ " '--component',\n",
+ " dest='comp_path',\n",
+ " action=\"store\",\n",
+ " required=True,\n",
+ " help=\"The path to the firmware file to upload\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-s',\n",
+ " '--session_key',\n",
+ " dest='session_key',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"Http session key for the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " required=False,\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " update_repo_flag = True\n",
+ " # Update the system with the firmware file\n",
+ " update_target_flag = False\n",
+ "\n",
+ " comp_type = 'C'\n",
+ " tpm_flag = True\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ " #system_url = \"https://\" + \"15.146.46.49\"\n",
+ " #session_id = \"515b196969f7d879886ee4a2da4ccba8\"\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " if options.session_key:\n",
+ " redfish_obj = RedfishClient(base_url=system_url, session_key= options.session_key)\n",
+ " else:\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(redfish_obj, options.comp_path, comp_type, update_repo_flag, update_target_flag)\n",
+ " if comp_type == 'C':\n",
+ " create_task(redfish_obj, options.comp_path, tpm_flag)\n",
+ "\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/generate_csr.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/generate_csr.ipynb
new file mode 100644
index 0000000..3dd1fc8
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/generate_csr.ipynb
@@ -0,0 +1,283 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "042acf39",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Generating a certificate signing request for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b34599c",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7338dfb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0c9837f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "034daf66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our generate csr function overview, in the end we will be able to make a certificate signing request.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
generate_csr function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about Http certificates is stored inside the
managers json object.\n",
+ " And now through managers_response variable, we are making a http
GET operation to and trying to obtain the certificates of signing of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system managers members response object with different
odata_id we get a security service uri .\n",
+ " Then again an http GET request is made and response is stored in
security_service_response.\n",
+ " Then we will make a http_cert_response by using csr_uri through security_service_response and then using http_cert_response we will get
generate_csr_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeHttpsCert attribute is present in
@odata.type attribute then we'll set csr_uri and
get generate csr uri of the target.\n",
+ "
\n",
+ "\n",
+ "5. If
generate_csr_uri exists, then we will define the body and send a
post request through redfish object. After generating the csr, we can obtain the
csr_response using
get method for csr_uri.
csr_response contains
CertificateSigningRequest. \n",
+ "\n",
+ "
\n",
+ "6. If you get the result, then it is successful. if you don't get the result, then there is an error.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "644bd708",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_csr(_redfishobj, csr_file, csr_properties):\n",
+ "\n",
+ " csr_uri = None\n",
+ " generate_csr_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " \n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " csr_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " https_cert_response = _redfishobj.get(csr_uri)\n",
+ " generate_csr_uri = https_cert_response.obj['Actions']['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " \n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " csr_uri = instance['@odata.id']\n",
+ " generate_csr_uri = _redfishobj.get(csr_uri).obj['Actions']['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " \n",
+ " break\n",
+ "\n",
+ " if generate_csr_uri:\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.GenerateCSR\"\n",
+ " body[\"City\"] = csr_properties[\"City\"]\n",
+ " body[\"CommonName\"] = csr_properties[\"CommonName\"]\n",
+ " body[\"Country\"] = csr_properties[\"Country\"]\n",
+ " body[\"OrgName\"] = csr_properties[\"OrgName\"]\n",
+ " body[\"OrgUnit\"] = csr_properties[\"OrgUnit\"]\n",
+ " body[\"State\"] = csr_properties[\"State\"]\n",
+ " resp = _redfishobj.post(generate_csr_uri, body)\n",
+ " if resp.status in [200, 201]:\n",
+ " sys.stdout.write(\"Generating CSR, this may take a few minutes\\n\")\n",
+ " sys.stdout.write(\"Sleeping for 5 minutes...\\n\")\n",
+ " time.sleep(600)\n",
+ " csr_resp = _redfishobj.get(csr_uri).dict['CertificateSigningRequest']\n",
+ " with open(csr_file, 'wb') as csroutput:\n",
+ " csroutput.write(csr_resp)\n",
+ " sys.stdout.write(\"CSR Data saved to file: '%s'\\n\" % csr_file)\n",
+ " else:\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status not in [200, 201]:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,sort_keys=True))\n",
+ " \n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\\n\")\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2da11ba0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter your ilo url,Username,Password here.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call generate_csr with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06934cbc",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46b3e899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #CSR Dictionary, each value should be updated to reflect the desired CSR\n",
+ " CSR_DICT = {\"City\" : input(\"Enter city:\"), \"CommonName\": input(\"Enter name:\"), \"Country\": input(\"Enter country :\"),\"OrgName\": input(\"Enter organization :\"), \"OrgUnit\": input(\"Enter unit :\"), \"State\": input(\"Enter state:\")}\n",
+ "\n",
+ " #After CSR is generated, a file will be created and the CSR will be downloaded\n",
+ " CSR_FILE = \"csr.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " generate_csr(REDFISHOBJ, CSR_FILE, CSR_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12c33902",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_SmartArray_EncryptionSettings.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_SmartArray_EncryptionSettings.ipynb
new file mode 100644
index 0000000..effd715
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_SmartArray_EncryptionSettings.ipynb
@@ -0,0 +1,229 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "24f88e8b",
+ "metadata": {},
+ "source": [
+ "Smart Array Encryption Settings On HPE ILO Systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91296f4e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98f640a8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c954abda",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e8336308",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about gathering the smart array encryption settings on HPE iLO systems
\n",
+ " \n",
+ "1. The function get_SmartArray_EncryptionSettings retrieves encryption settings for Smart Storage Array Controllers from a Redfish service.
\n",
+ "
\n",
+ " \n",
+ "2.It first checks if the resource directory is disabled or empty, and if so, it navigates through the Redfish service object to obtain the necessary URIs for Smart Storage Array Controllers
\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is enabled and not empty, the function uses the resource directory to find the relevant URI for Smart Storage Array Controllers.
\n",
+ "
\n",
+ "\n",
+ "4. It retrieves detailed information about each Smart Storage Array Controller and stores it in the smartarraycontrollers dictionary using the controller's @odata.id as the key.
\n",
+ "
\n",
+ "5. The function prints the encryption properties for each Smart Storage Array Controller, specifically the properties listed in the desired_properties list.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e85045dc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_SmartArray_EncryptionSettings(_redfishobj, desired_properties):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " smart_storage_uri = systems_members_response.obj.Oem.Hpe.Links['SmartStorage']['@odata.id']\n",
+ " smart_storage_arraycontrollers_uri = _redfishobj.get(smart_storage_uri).obj.Links['ArrayControllers']['@odata.id']\n",
+ " smartstorage_response = _redfishobj.get(smart_storage_arraycontrollers_uri).obj['Members']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeSmartStorageArrayControllerCollection.' in instance['@odata.type']:\n",
+ " smartstorage_uri = instance['@odata.id']\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ " break\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Encryption Properties for Smart Storage Array Controller \\'%s\\' : \\n% smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " for data in smartarraycontrollers[controller['@odata.id']]:\n",
+ " if data in desired_properties:\n",
+ " sys.stdout.write(\"\\t %s : %s\\n\" % (data, smartarraycontrollers[controller]['@odata.id']].get(data)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c776e47a",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2e71e12a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "05fc8da8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ " #list of desired properties related to Smart Array controller encryption\n",
+ " DESIRED_PROPERTIES = [\"Name\", \"Model\", \"SerialNumber\", \"EncryptionBootPasswordSet\",\"EncryptionCryptoOfficerPasswordSet\",\"EncryptionLocalKeyCacheEnabled\", \"EncryptionMixedVolumesEnabled\",\"EncryptionPhysicalDriveCount\", \"EncryptionRecoveryParamsSet\",\"EncryptionStandaloneModeEnabled\", \"EncryptionUserPasswordSet\"]\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_SmartArray_EncryptionSettings(REDFISHOBJ, DESIRED_PROPERTIES)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "123c6927",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_schema.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_schema.ipynb
new file mode 100644
index 0000000..fa974d7
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/get_schema.ipynb
@@ -0,0 +1,212 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "15565395",
+ "metadata": {},
+ "source": [
+ "System Schema Data
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd7d6791",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4ca0edc7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1805d6fa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "404a5487",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about obtaining system schema data
\n",
+ " \n",
+ "1. The function takes a parameter, _redfishobj, which represents the Redfish service object used to interact with the API.
\n",
+ "
\n",
+ " \n",
+ "2.It initializes two variables: schema_members_uris and schema_members_expanded. schema_members_uris is an empty list that will store the URIs of schema members, while schema_members_expanded is an empty dictionary that will hold the expanded schema information.
\n",
+ "
\n",
+ "\n",
+ "3. It retrieves the URI for the root JSON schema from the Redfish service object (_redfishobj) and makes a GET request to obtain the schema response. The response contains a list of member URIs that point to individual schemas.
\n",
+ "
\n",
+ "\n",
+ "4. The function iterates through each member URI, retrieves the schema data, and expands the URI link for sub-schemas with the actual schema information. The expanded schema data is stored in the schema_members_expanded dictionary using the member URI as the key.
\n",
+ "
\n",
+ "5. The function iterates through each member URI, retrieves the schema data, and expands the URI link for sub-schemas with the actual schema information. The expanded schema data is stored in the schema_members_expanded dictionary using the member URI as the key.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "780095b1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_schema(_redfishobj):\n",
+ " schema_members_uris = []\n",
+ " schema_members_expanded = {}\n",
+ "\n",
+ " schema_uri = _redfishobj.root.obj['JsonSchemas']['@odata.id']\n",
+ " schema_response = _redfishobj.get(schema_uri)\n",
+ " schema_members_uris = schema_response.obj['Members']\n",
+ " for member in schema_members_uris:\n",
+ " data = _redfishobj.get(member['@odata.id']).dict\n",
+ " instance_id = data['Location'].index(next(iter(data['Location'])))\n",
+ " schema_uri = data['Location'][instance_id]['Uri']\n",
+ " schema = _redfishobj.get(schema_uri).dict\n",
+ " #I am just replacing the URI link for the sub-schema with the actual schema. You will\n",
+ " #see EVERYTHING\n",
+ " _tmp = {schema_uri + ' ->': schema}\n",
+ " data['Location'][instance_id]['Uri'] = _tmp\n",
+ " schema_members_expanded[member['@odata.id']] = data\n",
+ "\n",
+ " print(json.dumps(schema_members_expanded, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "071606d1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "275fe668",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a1f63d79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_schema(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d740355",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/mount_virtual_media.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/mount_virtual_media.ipynb
new file mode 100644
index 0000000..6392a29
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/mount_virtual_media.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "71861904",
+ "metadata": {},
+ "source": [
+ "Mount Virtual Media Iso
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.This is our mount_virtual_media_iso function overview, in the end this will give us with virtual media related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the virtual media information.\n",
+ "\n",
+ "1. In the
mount_virtual_media_iso function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about virtual media is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the virtual media about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The virtual media information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if virtual media is present in
@odata.type attribute then we will store information about virtual media in virtual_media_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if virtual_media_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, media_type):\n",
+ "\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.EjectMedia']['target']\n",
+ " post_body = {\"Action\": \"HpeiLOVirtualMedia.EjectVirtualMedia\"}\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter a redfish obejct is created with the help of RedfishClient
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90621a8a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 25\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 26\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 27\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 31\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 30\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 31\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 32\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 33\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = input(\"Enter type of media\") #current possible options: Floppy, USBStick, CD, DVD\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ "\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_TYPE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/sessions.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/sessions.ipynb
new file mode 100644
index 0000000..25877ef
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/sessions.ipynb
@@ -0,0 +1,234 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ " Manually Managing Sessions With Redfish
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from six.moves import urllib\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about sessions function
\n",
+ " \n",
+ "1. This function creates a new session with an iLO server using provided login credentials..
\n",
+ "
\n",
+ " \n",
+ "2. The function sends a POST request to the /redfish/v1/Sessions endpoint to create the session..
\n",
+ "
\n",
+ "\n",
+ "3. If the session is created successfully (response code 201), the function prints the session URI and X-Auth Token key..
\n",
+ "
\n",
+ "\n",
+ "4. The function also sends a DELETE request to the session URI to terminate the session.
\n",
+ "
\n",
+ "5. If the session creation fails, the function prints an error message and tries to access the iLO Extended Message Info for more details..
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def sessions(_redfishobj, login_account, login_password):\n",
+ "\n",
+ " new_session = {\"UserName\": login_account, \"Password\": login_password}\n",
+ " response = _redfishobj.post('/redfish/v1/Sessions', new_session)\n",
+ "\n",
+ " if response.status == 201:\n",
+ " print(\"Success!\\n\")\n",
+ " session_uri = response.getheader(\"location\")\n",
+ " session_uri = urllib.parse.urlparse(session_uri)\n",
+ " sys.stdout.write(\"\\tSession \" + session_uri.path + \" created.\\n\")\n",
+ " x_auth_token = response.getheader(\"x-auth-token\")\n",
+ " sys.stdout.write(\"\\tThis is the session X-Auth Token key \" + x_auth_token + \".\\n\")\n",
+ " print(json.dumps(response.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " # Delete the created session\n",
+ " sys.stdout.write(\"\\tTerminating this session.\\n\")\n",
+ " sessresp = _redfishobj.delete(session_uri.path)\n",
+ " print(json.dumps(sessresp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"ERROR: failed to create a session.\\n\")\n",
+ " try:\n",
+ " print(json.dumps(sessresp.obj['error']['@Message.ExtendedInfo'], indent=4,sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended\"\n",
+ " \" Message Info...\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ " Once your credentials that are enter a redfish obejct is created with the help of RedfishClient \n",
+ " If server is down or Unreachable we get server not reachable message!\n",
+ " If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.\n",
+ " After getting required information Redfish.logout() closses the particular session and logs us out of the system.\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " sessions(REDFISHOBJ, LOGIN_ACCOUNT, LOGIN_PASSWORD)#calling sessions function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "316c3f0e",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_PrimaryKeyServer.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_PrimaryKeyServer.ipynb
new file mode 100644
index 0000000..648e76d
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_PrimaryKeyServer.ipynb
@@ -0,0 +1,273 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Set_ESKM_PrimaryKeyServer
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about set_ESKM_PrimaryKeyServer function
\n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ "1. This function sets the primary key server for the HPE ESKM service.
\n",
+ "
\n",
+ " \n",
+ "2. It takes three arguments: _redfishobj (an object representing the Redfish service), primary_key_server_address (a string representing the IP address or hostname of the primary key server), and primary_key_server_port (an integer representing the port number of the primary key server).
\n",
+ "
\n",
+ "\n",
+ "3. It uses the get_resource_directory function to find the relevant ESKM URI, which is used to make a POST request to set the primary key server.
\n",
+ "
\n",
+ "\n",
+ "4. If the POST request is successful (returns an HTTP status code of 200), the function prints a success message and the JSON response from the server.
\n",
+ "
\n",
+ "5. If the POST request is unsuccessful, the function prints an error message and, if available, the extended error information from the server response.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ESKM_PrimaryKeyServer(_redfishobj, primary_key_server_address, primary_key_server_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " \n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ "\n",
+ " body[\"PrimaryKeyServerAddress\"] = primary_key_server_address\n",
+ " body[\"PrimaryKeyServerPort\"] = int(primary_key_server_port)\n",
+ "\n",
+ " resp = _redfishobj.post(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,sort_keys=True))\n",
+ " \n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " \n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are entered a redfish obejct is created with the help of RedfishClient .
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " PRIMARY_KEY_SERVER_ADDRESS = input(\"Enter server address\")\n",
+ " PRIMARY_KEY_SERVER_PORT = int(input(\"Enter server port\"))\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ESKM_PrimaryKeyServer(REDFISHOBJ, PRIMARY_KEY_SERVER_ADDRESS, PRIMARY_KEY_SERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_username_password.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_username_password.ipynb
new file mode 100644
index 0000000..8acab71
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_ESKM_username_password.ipynb
@@ -0,0 +1,273 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Setting the ESKM username and password for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about ESKM_username_pass function
\n",
+ " \n",
+ "1. The function sets up an Electronic Software Key Manager (ESKM) on an iLO (Integrated Lights Out) server using the Redfish API.
\n",
+ "
\n",
+ " \n",
+ "2. It takes several input parameters including ESKM username, password, account group, primary key server address, and primary key server port.
\n",
+ "
\n",
+ "\n",
+ "3. It first attempts to locate the URI for the ESKM resource either by using the Redfish Resource Directory or by manually navigating through the Redfish API.br>\n",
+ "
\n",
+ "\n",
+ "4. If the ESKM URI is found, the function constructs a JSON payload containing the ESKM configuration information and primary key server details and sends it as a PATCH request to the ESKM resource.
\n",
+ "
\n",
+ "5. If the PATCH request is successful (i.e., returns an HTTP status code of 200), the function prints out a success message along with the response payload, otherwise it prints out an error message.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ESKM_username_pass(_redfishobj, eskm_username, eskm_password, eskm_accountgroup,eskm_primarykeyserver_addr, eskm_primarykeyserver_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " \n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " body[\"KeyManagerConfig\"] = dict()\n",
+ " body[\"KeyManagerConfig\"][\"LoginName\"] = eskm_username\n",
+ " body[\"KeyManagerConfig\"][\"Password\"] = eskm_password\n",
+ " body[\"KeyManagerConfig\"][\"AccountGroup\"] = eskm_accountgroup\n",
+ " body[\"KeyManagerConfig\"][\"ESKMLocalCACertificateName\"] = \"\"\n",
+ " body[\"PrimaryKeyServerAddress\"] = eskm_primarykeyserver_addr\n",
+ " body[\"PrimaryKeyServerPort\"] = eskm_primarykeyserver_port\n",
+ " resp = _redfishobj.patch(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " \n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " \n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are entered a redfish obejct is created with the help of RedfishClient.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " ESKM_USERNAME = input(\"Enter username\")\n",
+ " ESKM_PASSWORD = input(\"Enter password\")\n",
+ " ESKM_ACCOUNTGROUP = input(\"Enter account group\")\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR = input(\"Enter server address\")\n",
+ " ESKM_PRIMARYKEYSERVER_PORT = int(input(\"Enter server port\"))\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " ESKM_username_pass(REDFISHOBJ, ESKM_USERNAME, ESKM_PASSWORD, ESKM_ACCOUNTGROUP,ESKM_PRIMARYKEYSERVER_ADDR, ESKM_PRIMARYKEYSERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a73f3528",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " 4.Changing Boot Setting Documentation:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_active_ilo_nic.ipynb b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_active_ilo_nic.ipynb
new file mode 100644
index 0000000..f424eac
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/B VENKAT RAHUL/set_active_ilo_nic.ipynb
@@ -0,0 +1,279 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Setting the active Manager NIC
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is about set_active_ilo_nic function
\n",
+ " \n",
+ "\n",
+ "1. This function is used to enable/disable Ethernet interfaces on an iLO (Integrated Lights Out) management interface.
\n",
+ "
\n",
+ " \n",
+ "2. The function first gets a list of available Ethernet interfaces using the Redfish API, which is a standard RESTful interface for managing servers.
\n",
+ "
\n",
+ "\n",
+ "3. The function first gets a list of available Ethernet interfaces using the Redfish API, which is a standard RESTful interface for managing servers.
\n",
+ "
\n",
+ "\n",
+ "4. If the PATCH request is successful (HTTP status 200), the function prints a success message and the response body, which contains information about the updated Ethernet interface.
\n",
+ "
\n",
+ "5. Finally, the function reminds the user that they need to reset iLO for the change to take effect.
\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b99181a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_active_ilo_nic(_redfishobj):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']['@odata.id']\n",
+ " \n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.obj['Members']\n",
+ " \n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in instance['@odata.id']:\n",
+ " \n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.get(_ethernet_interface['@odata.id']).dict\n",
+ " \n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " for interface in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Management Inteface \\'%s\\'\\n\" % ethernet_data[interface].get('Id'))\n",
+ " \n",
+ " sys.stdout.write(\"\\t\\'Interface Enabled\\': %s\\n\" % ethernet_data[interface].get('InterfaceEnabled'))\n",
+ "\n",
+ " \n",
+ " for ethernet in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Interface: %s\\n\" % ethernet)\n",
+ " ans = input(\"Would you like to enable/disable this interface? (enable/disable)\\n\")\n",
+ " if \"en\" in ans:\n",
+ " body = {\"InterfaceEnabled\": True}\n",
+ " else:\n",
+ " body = {\"InterfaceEnabled\": False}\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,sort_keys=True))\n",
+ " \n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! You will need to reset iLO for this change to take effect.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "031a5cbe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are entered a redfish obejct is created with the help of RedfishClient .
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0b490052",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_active_ilo_nic(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "316c3f0e",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.HPE ilorest-api explorer:
LINK\n",
+ " 3.REST API:
LINK\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acc45fbf",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/.ipynb_checkpoints/index-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/.ipynb_checkpoints/index-checkpoint.ipynb
new file mode 100644
index 0000000..6bb46a5
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/.ipynb_checkpoints/index-checkpoint.ipynb
@@ -0,0 +1,303 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "Scripts related to BIOS
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fa8b0fad",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change BIOS Settings | \n",
+ " Update BIOS Settings for iLO server | \n",
+ " PATCH | \n",
+ " BIOS_ChangeSettings | \n",
+ "
\n",
+ " \n",
+ " | BIOS Default | \n",
+ " Update BIOS to default setting | \n",
+ " POST | \n",
+ " BIOS_RevertToDefault | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "Scripts related to Users
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf10b943",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Add User Account | \n",
+ " Add new user account | \n",
+ " PATCH | \n",
+ " Add user account | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e16cdec",
+ "metadata": {},
+ "source": [
+ "Scripts related to Booting
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616fef86",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change Boot Order | \n",
+ " Change iLOs boot ordert | \n",
+ " PATCH | \n",
+ " Change_Boot_Order | \n",
+ "
\n",
+ " \n",
+ " | Change Temporary Boot Order | \n",
+ " Change iLOs temporary boot ordert | \n",
+ " PATCH | \n",
+ " Change_Temp_Boot_Order | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a39acd4",
+ "metadata": {},
+ "source": [
+ "Scripts related to Firmware
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7f7d0e2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Upload Firmware to iLO repository | \n",
+ " Script for uploading firmware to the iLO Repository for flashing | \n",
+ " | \n",
+ " Upload_Firmware_to_iLO_repo | \n",
+ "
\n",
+ " \n",
+ " | Upload Firmware with associated COMPSIG file to iLO repository | \n",
+ " Script for uploading a firmware component with a size less than\n",
+ "32 GB, and associated Component Signature (compsig) signature file to the iLO Repository | \n",
+ " | \n",
+ " Upload_Firmware_iLO_Repo_with_COMPSIG | \n",
+ "
\n",
+ " \n",
+ " | Update Firmware | \n",
+ " Script for updating Firmware via HTTP URL | \n",
+ " | \n",
+ " Update_iLO_Firmware | \n",
+ "
\n",
+ " \n",
+ " | View Firmware Inventory | \n",
+ " Script for viewing the firmware inventory on HPE iLO systems | \n",
+ " | \n",
+ " Software_Firmware_Inventory | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a224da35",
+ "metadata": {},
+ "source": [
+ "Scripts related to ESKM (Enterprise Secure Key Manager)
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b44242b9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Test ESKM Connection | \n",
+ " Script for testing connection to the ESKM system for HPE iLO systems | \n",
+ " | \n",
+ " Test_ESKM_Connection | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a0d4cfe3",
+ "metadata": {},
+ "source": [
+ "Scripts related to Power
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e8055b18",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get Power Metrics Average | \n",
+ " Script for gathering the power metrics average on HPE iLO systems | \n",
+ " | \n",
+ " Get_Powermetrics_Average | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bcbac905",
+ "metadata": {},
+ "source": [
+ "Miscellaneous Scripts
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "610e17bf",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Example Data Resopnses | \n",
+ " Example Script for expanding data responses | \n",
+ " | \n",
+ " Expand_data | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "347cbdcf",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_ChangeSettings-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_ChangeSettings-checkpoint.ipynb
new file mode 100644
index 0000000..f9f4268
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_ChangeSettings-checkpoint.ipynb
@@ -0,0 +1,278 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "25002fd3",
+ "metadata": {},
+ "source": [
+ "Change BIOS Settings
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6a14567a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b0a99221",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bb04ead1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8505c876",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change bios settings function overview, in the end this will be able to change the bios settings.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
change_bios_settings function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a BIOS URI .\n",
+ " Then again an http GET request is made and response is stored in
systems_response.\n",
+ " Then we set the systems_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e., resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios data of the user through redfish object. Now we will get the bios_settings_uri through bios_data object.\n",
+ "
\n",
+ "\n",
+ "5. Then if bios password is present, then we will update the bios password. Finally we will send
patch request from redfish object using
bios_setting_uri. \n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then we will get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "243405a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_bios_setting(_redfishobj, bios_property, property_value, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if bios_uri:\n",
+ " #BIOS settings URI is needed\n",
+ " \n",
+ " bios_settings_uri = bios_data.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " body = {'Attributes': {bios_property: property_value}}\n",
+ " \n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " resp = _redfishobj.patch(bios_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " #uncomment if you would like to see the full list of attributes\n",
+ " #print(\"\\n\\nShowing BIOS attributes after changes:\\n\\n\")\n",
+ " #bios_data = _redfishobj.get(bios_uri)\n",
+ " #print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2c62673d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Please enter iLO url, username, password, bios attribute, attribute_value and bios password when asked.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_bios_settings with our redfish object and the attribute we need and change and the value along with the bios password.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1f44368d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14547cd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = getpass.getpass(\"Enter bios password: \")\n",
+ " \n",
+ " #provide the attribute name and the associated attribute value. Note: some, values may\n",
+ " #be containers (arrays or dictionaries) so keep this in mind.\n",
+ " \n",
+ " ATTRIBUTE = input(\"Enter bios property you wish to change (Example: AdminName): \")\n",
+ " ATTRIBUTE_VAL = input(\"Enter Value of the property to change (Example: Luigi): \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_bios_setting(REDFISHOBJ, ATTRIBUTE, ATTRIBUTE_VAL, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91b6f3c6",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_RevertToDefault-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_RevertToDefault-checkpoint.ipynb
new file mode 100644
index 0000000..461f4d2
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/BIOS_RevertToDefault-checkpoint.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ad9eed9d",
+ "metadata": {},
+ "source": [
+ "Reverting the BIOS to it's default values
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bdc5c94",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b6adafee",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2c1c9a1c",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "# Import the required libraries\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "# Import the helper function\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "397110c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a HTTP
GET operation and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an HTTP GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "91157e79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bios_revert_default(_redfishobj):\n",
+ " # Initialize the BIOS reset action URI (Uniform Resource Identifier)\n",
+ " bios_reset_action_uri = None\n",
+ " \n",
+ " # Get the resource directory to find the relevant URI\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " # If resource directory is not available or not to be used, find the relevant URI\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " # Get the systems URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " \n",
+ " # Get the systems members URI\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " \n",
+ " # Get the BIOS URI\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " \n",
+ " # Get the BIOS reset action URI\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " # Use resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ " \n",
+ " # Define the body for the POST request\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType': 'default'}\n",
+ " \n",
+ " # Send the POST request\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ " \n",
+ " # Check the response status\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b26b9819",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9886e56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fbdb430d",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " # Call the function to revert BIOS to default values\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ "\n",
+ " # Logout from the Redfish client\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f8583d9",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb
new file mode 100644
index 0000000..3144945
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb
@@ -0,0 +1,259 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reverting the BIOS to default values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reset your bios to default settings!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "658962be-a0df-4696-ab9e-73f844703ff9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "53341fc4-f674-4781-bcb1-04bb06d3d1fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an http GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a5f7d7b2-6ab5-473d-ba19-113d603f9e2d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def bios_revert_default(_redfishobj):\n",
+ "\n",
+ " bios_reset_action_uri = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ "\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType':'default'}\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0ded655-d8e4-452d-b181-783a6b1788f5",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_ChangeSettings.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_ChangeSettings.ipynb
new file mode 100644
index 0000000..f9f4268
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_ChangeSettings.ipynb
@@ -0,0 +1,278 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "25002fd3",
+ "metadata": {},
+ "source": [
+ "Change BIOS Settings
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6a14567a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b0a99221",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bb04ead1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8505c876",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change bios settings function overview, in the end this will be able to change the bios settings.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
change_bios_settings function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a BIOS URI .\n",
+ " Then again an http GET request is made and response is stored in
systems_response.\n",
+ " Then we set the systems_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e., resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios data of the user through redfish object. Now we will get the bios_settings_uri through bios_data object.\n",
+ "
\n",
+ "\n",
+ "5. Then if bios password is present, then we will update the bios password. Finally we will send
patch request from redfish object using
bios_setting_uri. \n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then we will get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "243405a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_bios_setting(_redfishobj, bios_property, property_value, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if bios_uri:\n",
+ " #BIOS settings URI is needed\n",
+ " \n",
+ " bios_settings_uri = bios_data.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " body = {'Attributes': {bios_property: property_value}}\n",
+ " \n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " resp = _redfishobj.patch(bios_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " #uncomment if you would like to see the full list of attributes\n",
+ " #print(\"\\n\\nShowing BIOS attributes after changes:\\n\\n\")\n",
+ " #bios_data = _redfishobj.get(bios_uri)\n",
+ " #print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2c62673d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " Please enter iLO url, username, password, bios attribute, attribute_value and bios password when asked.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_bios_settings with our redfish object and the attribute we need and change and the value along with the bios password.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1f44368d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14547cd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = getpass.getpass(\"Enter bios password: \")\n",
+ " \n",
+ " #provide the attribute name and the associated attribute value. Note: some, values may\n",
+ " #be containers (arrays or dictionaries) so keep this in mind.\n",
+ " \n",
+ " ATTRIBUTE = input(\"Enter bios property you wish to change (Example: AdminName): \")\n",
+ " ATTRIBUTE_VAL = input(\"Enter Value of the property to change (Example: Luigi): \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_bios_setting(REDFISHOBJ, ATTRIBUTE, ATTRIBUTE_VAL, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91b6f3c6",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_RevertToDefault.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_RevertToDefault.ipynb
new file mode 100644
index 0000000..461f4d2
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BIOS/BIOS_RevertToDefault.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ad9eed9d",
+ "metadata": {},
+ "source": [
+ "Reverting the BIOS to it's default values
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bdc5c94",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b6adafee",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2c1c9a1c",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "# Import the required libraries\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "# Import the helper function\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "397110c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a HTTP
GET operation and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an HTTP GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "91157e79",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bios_revert_default(_redfishobj):\n",
+ " # Initialize the BIOS reset action URI (Uniform Resource Identifier)\n",
+ " bios_reset_action_uri = None\n",
+ " \n",
+ " # Get the resource directory to find the relevant URI\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " # If resource directory is not available or not to be used, find the relevant URI\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " # Get the systems URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " \n",
+ " # Get the systems members URI\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " \n",
+ " # Get the BIOS URI\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " \n",
+ " # Get the BIOS reset action URI\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " # Use resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ " \n",
+ " # Define the body for the POST request\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType': 'default'}\n",
+ " \n",
+ " # Send the POST request\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ " \n",
+ " # Check the response status\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b26b9819",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO URL, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9886e56",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fbdb430d",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " # Call the function to revert BIOS to default values\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ "\n",
+ " # Logout from the Redfish client\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f8583d9",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Boot_Order-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Boot_Order-checkpoint.ipynb
new file mode 100644
index 0000000..6ff5922
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Boot_Order-checkpoint.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e8359fe6",
+ "metadata": {},
+ "source": [
+ "Change Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8cb46c69",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6557d8e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9dc3d6d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7753861c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change boot order function overview, in the end this will change the boot order by one position.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. This function initializes bios_boot_uri and bios_boot_response variables to None.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find bios_boot_uri. If bios_boot_uri is not None, retrieve the BIOS boot settings using get() method. Then Retrieve the URI for BIOS boot settings from the response.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "4. If bios_password is provided, update the BIOS password with it.\n",
+ "
\n",
+ "\n",
+ "5. Print the current boot order. Rotate the first boot device to the end of the boot order. Update the boot order using the patch() method with the new boot order.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated BIOS boot settings.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9740789",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_boot_order(_redfishobj, bios_password):\n",
+ "\n",
+ " bios_boot_uri = None\n",
+ " bios_boot_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_boot_uri = bios_response.obj.Oem.Hpe.Links.Boot['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeServerBootSettings.' in instance['@odata.type']:\n",
+ " bios_boot_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_boot_uri:\n",
+ " bios_boot_response = _redfishobj.get(bios_boot_uri)\n",
+ " #Bios boot settings URI is needed\n",
+ " bios_boot_settings_uri = bios_boot_response.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " sys.stdout.write(\"Rotating the first boot device to the end of the boot order.\\n\")\n",
+ " sys.stdout.write('Current Order:\\n')\n",
+ " boot_order = bios_boot_response.obj['DefaultBootOrder']\n",
+ " for indx, boot_device in enumerate(boot_order):\n",
+ " sys.stdout.write('Pos ' + str(indx) + ' : ' + boot_device + '\\n')\n",
+ " device = boot_order.pop(0)\n",
+ " sys.stdout.write(\"Rotating device: \\'%s\\' to the end of the boot order.\\n\" % device)\n",
+ " boot_order.append(device)\n",
+ "\n",
+ " body = {'DefaultBootOrder': boot_order}\n",
+ " resp = _redfishobj.patch(bios_boot_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! Your system may need to be restarted.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"Unable to find Boot Order URI.\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17889355",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_boot_order function with our redfish object and BIOS Password as parameters
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "73d96a09",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cba1616",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = None\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_boot_order(REDFISHOBJ, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f00caf4",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Temp_Boot_Order-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Temp_Boot_Order-checkpoint.ipynb
new file mode 100644
index 0000000..9337b80
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/.ipynb_checkpoints/Change_Temp_Boot_Order-checkpoint.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a9b0b4a",
+ "metadata": {},
+ "source": [
+ "Change Temporary Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04e1b75",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f33ca630",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0058d42d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d69021c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change temporary boot order function overview, in the end this will set the boot order temporarily to the device stored in \"boottarget\" variable.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ " \n",
+ "2. This function first calls get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find systems_members_uri where we can set the temporary boot target. If systems_members_uri is not None, then set the attribute 'BootSourceOverrideTarget' to 'boottarget' varible.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated boot override target.\n",
+ " \n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aaba46fd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_temporary_boot_order(_redfishobj, boottarget):\n",
+ "\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))\n",
+ " body = {'Boot': {'BootSourceOverrideTarget': boottarget}}\n",
+ " resp = _redfishobj.patch(systems_members_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing boot override target:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2405f770",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the temporary boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of _REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "4. When asked to enter Temporary Boot Device, enter desired temporary boot device (Example: Hdd)
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Then we call change_temporary_boot_order function with our redfish object and chosen temporary boot device as parameters
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4d5f0843",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b43b7a95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # string to represent the selected temporary boot device\n",
+ " TEMP_DEVICE = input(\"Enter temporary boot device: \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_temporary_boot_order(REDFISHOBJ, TEMP_DEVICE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9784ce2a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Boot_Order.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Boot_Order.ipynb
new file mode 100644
index 0000000..6ff5922
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Boot_Order.ipynb
@@ -0,0 +1,274 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e8359fe6",
+ "metadata": {},
+ "source": [
+ "Change Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8cb46c69",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6557d8e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9dc3d6d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7753861c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change boot order function overview, in the end this will change the boot order by one position.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. This function initializes bios_boot_uri and bios_boot_response variables to None.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find bios_boot_uri. If bios_boot_uri is not None, retrieve the BIOS boot settings using get() method. Then Retrieve the URI for BIOS boot settings from the response.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "4. If bios_password is provided, update the BIOS password with it.\n",
+ "
\n",
+ "\n",
+ "5. Print the current boot order. Rotate the first boot device to the end of the boot order. Update the boot order using the patch() method with the new boot order.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated BIOS boot settings.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9740789",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_boot_order(_redfishobj, bios_password):\n",
+ "\n",
+ " bios_boot_uri = None\n",
+ " bios_boot_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_boot_uri = bios_response.obj.Oem.Hpe.Links.Boot['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeServerBootSettings.' in instance['@odata.type']:\n",
+ " bios_boot_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_boot_uri:\n",
+ " bios_boot_response = _redfishobj.get(bios_boot_uri)\n",
+ " #Bios boot settings URI is needed\n",
+ " bios_boot_settings_uri = bios_boot_response.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " sys.stdout.write(\"Rotating the first boot device to the end of the boot order.\\n\")\n",
+ " sys.stdout.write('Current Order:\\n')\n",
+ " boot_order = bios_boot_response.obj['DefaultBootOrder']\n",
+ " for indx, boot_device in enumerate(boot_order):\n",
+ " sys.stdout.write('Pos ' + str(indx) + ' : ' + boot_device + '\\n')\n",
+ " device = boot_order.pop(0)\n",
+ " sys.stdout.write(\"Rotating device: \\'%s\\' to the end of the boot order.\\n\" % device)\n",
+ " boot_order.append(device)\n",
+ "\n",
+ " body = {'DefaultBootOrder': boot_order}\n",
+ " resp = _redfishobj.patch(bios_boot_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! Your system may need to be restarted.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " else:\n",
+ " sys.stderr.write(\"Unable to find Boot Order URI.\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17889355",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_boot_order function with our redfish object and BIOS Password as parameters
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "73d96a09",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cba1616",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = None\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_boot_order(REDFISHOBJ, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2f00caf4",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Temp_Boot_Order.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Temp_Boot_Order.ipynb
new file mode 100644
index 0000000..9337b80
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/BOOT/Change_Temp_Boot_Order.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1a9b0b4a",
+ "metadata": {},
+ "source": [
+ "Change Temporary Boot Order
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04e1b75",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f33ca630",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0058d42d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d69021c8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our change temporary boot order function overview, in the end this will set the boot order temporarily to the device stored in \"boottarget\" variable.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ " \n",
+ "2. This function first calls get_resource_directory() function by passing the \"_redfishobj\" as parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then we navigate through the hirerachy to find systems_members_uri where we can set the temporary boot target. If systems_members_uri is not None, then set the attribute 'BootSourceOverrideTarget' to 'boottarget' varible.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the updated boot override target.\n",
+ " \n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aaba46fd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_temporary_boot_order(_redfishobj, boottarget):\n",
+ "\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))\n",
+ " body = {'Boot': {'BootSourceOverrideTarget': boottarget}}\n",
+ " resp = _redfishobj.patch(systems_members_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " if systems_members_response:\n",
+ " print(\"\\n\\nShowing boot override target:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict.get('Boot'), indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2405f770",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the temporary boot order.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of _REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "4. When asked to enter Temporary Boot Device, enter desired temporary boot device (Example: Hdd)
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Then we call change_temporary_boot_order function with our redfish object and chosen temporary boot device as parameters
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4d5f0843",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b43b7a95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # string to represent the selected temporary boot device\n",
+ " TEMP_DEVICE = input(\"Enter temporary boot device: \")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_temporary_boot_order(REDFISHOBJ, TEMP_DEVICE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9784ce2a",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/.ipynb_checkpoints/Test_ESKM_Connection-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/.ipynb_checkpoints/Test_ESKM_Connection-checkpoint.ipynb
new file mode 100644
index 0000000..780ec30
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/.ipynb_checkpoints/Test_ESKM_Connection-checkpoint.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "17caee10",
+ "metadata": {},
+ "source": [
+ "Test ESKM Connection
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ca92dce",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d5c69ec2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "149adcfa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c74f9b37",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our test_ESKM_connection function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The test_ESKM_connection_ilo_firmware function takes one parameter - _redfishobj.\n",
+ "
\n",
+ " \n",
+ "2. Initialize the eskm_uri and body variables to None and an empty dictionary, respectively.\n",
+ "
\n",
+ "\n",
+ "3. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "5. Check if eskm_uri has been set. If eskm_uri is not None, retrieve the URI for the ESKM service.\n",
+ "
\n",
+ "\n",
+ "6. If the ESKM URI is available, retrieve the URI for testing the ESKM connection from the response.\n",
+ "
\n",
+ "\n",
+ "7. Set the Action field of the body dictionary to \"HpeESKM.TestESKMConnections\".\n",
+ "
\n",
+ " \n",
+ "8. Call the post() method of the _redfishobj object with the ESKM test connection URI and the body dictionary as parameters.\n",
+ "
\n",
+ " \n",
+ "9. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the JSON-formatted response.\n",
+ " \n",
+ " \n",
+ "10. If eskm_uri is None, print an error message.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "96ac0e95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def test_ESKM_connection(_redfishobj):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ "\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " eskm_test_conn_uri = _redfishobj.get(eskm_uri).obj['Actions']['#HpeESKM.TestESKMConnections']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.TestESKMConnections\"\n",
+ " resp = _redfishobj.post(eskm_test_conn_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "beb17e66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to test connection to ESKM Systems.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. Then we call test_ESKM_connection with our redfish object as parameter.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "571dd05d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09b2811e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " test_ESKM_connection(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0cdf874",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/Test_ESKM_Connection.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/Test_ESKM_Connection.ipynb
new file mode 100644
index 0000000..780ec30
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/ESKM/Test_ESKM_Connection.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "17caee10",
+ "metadata": {},
+ "source": [
+ "Test ESKM Connection
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ca92dce",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d5c69ec2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "149adcfa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c74f9b37",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our test_ESKM_connection function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The test_ESKM_connection_ilo_firmware function takes one parameter - _redfishobj.\n",
+ "
\n",
+ " \n",
+ "2. Initialize the eskm_uri and body variables to None and an empty dictionary, respectively.\n",
+ "
\n",
+ "\n",
+ "3. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "5. Check if eskm_uri has been set. If eskm_uri is not None, retrieve the URI for the ESKM service.\n",
+ "
\n",
+ "\n",
+ "6. If the ESKM URI is available, retrieve the URI for testing the ESKM connection from the response.\n",
+ "
\n",
+ "\n",
+ "7. Set the Action field of the body dictionary to \"HpeESKM.TestESKMConnections\".\n",
+ "
\n",
+ " \n",
+ "8. Call the post() method of the _redfishobj object with the ESKM test connection URI and the body dictionary as parameters.\n",
+ "
\n",
+ " \n",
+ "9. If the HTTP response status code is not 200 or 201, print an error message. If the HTTP response status code is 400, print the iLO extended info error message. If the HTTP response status code is 200 or 201, print a success message and the JSON-formatted response.\n",
+ " \n",
+ " \n",
+ "10. If eskm_uri is None, print an error message.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "96ac0e95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def test_ESKM_connection(_redfishobj):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ "\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " eskm_test_conn_uri = _redfishobj.get(eskm_uri).obj['Actions']['#HpeESKM.TestESKMConnections']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.TestESKMConnections\"\n",
+ " resp = _redfishobj.post(eskm_test_conn_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "beb17e66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to test connection to ESKM Systems.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. Then we call test_ESKM_connection with our redfish object as parameter.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "571dd05d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09b2811e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " test_ESKM_connection(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0cdf874",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Software_Firmware_Inventory-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Software_Firmware_Inventory-checkpoint.ipynb
new file mode 100644
index 0000000..f0253db
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Software_Firmware_Inventory-checkpoint.ipynb
@@ -0,0 +1,288 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "90595900",
+ "metadata": {},
+ "source": [
+ "Script for viewing the firmware inventory on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "887d7741",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "830d2b30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2a88487d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "827bf8e1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_inventory_uri function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function initializes the update_service_uri and inventory_uri variables to None.
\n",
+ " \n",
+ "2. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.
\n",
+ "\n",
+ "3. If the resource directory is available, find the relevant URI from the resource directory.
\n",
+ "\n",
+ "4. Check if update_service_uri has been set. If update_service_uri is not None, retrieve the URI for the update service.
\n",
+ "\n",
+ "5. Retrieve the update service response using the get() method on _redfishobj. If the provided selection contains the word \"software\" (case insensitive), set the inventory_uri to the URI of the software inventory obtained from the update service response.
\n",
+ "\n",
+ "6. If the provided selection contains the word \"firmware\" (case insensitive), set the inventory_uri to the URI of the firmware inventory obtained from the update service response.
\n",
+ " \n",
+ "7. If an invalid selection is provided, raise an exception with an error message.
\n",
+ " \n",
+ "8. Print the inventory URI.
\n",
+ " \n",
+ "9. Call the get_inventory() function, passing _redfishobj and inventory_uri as parameters.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a11214ba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory_uri(_redfishobj, select):\n",
+ "\n",
+ " update_service_uri = None\n",
+ " inventory_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if update_service_uri:\n",
+ " update_service_resp = _redfishobj.get(update_service_uri)\n",
+ " if \"software\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['SoftwareInventory']['@odata.id']\n",
+ " elif \"firmware\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['FirmwareInventory']['@odata.id']\n",
+ " else:\n",
+ " raise Exception(\"Invalid selection provided: Please select 'software' or 'firmware' to obtain the relevant invetory data.\")\n",
+ " sys.stdout.write(\"Printing data in invetory: %s\\n\" % inventory_uri)\n",
+ " get_inventory(_redfishobj, inventory_uri)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c329bc0f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is our get_inventory function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function retrieves the list of members from the provided inventory_uri using the get() method on _redfishobj.
\n",
+ " \n",
+ "2. If there are no members in the inventory, print a message indicating that the inventory is empty.
\n",
+ "\n",
+ "3. Iterate over each inventory item in the list of members.
\n",
+ "\n",
+ "4. Retrieve the details of each inventory item using the get() method on _redfishobj with the item's URI.
\n",
+ "\n",
+ "5. Print the name and description of the inventory item.
\n",
+ "\n",
+ "6. Print the JSON-formatted contents of the inventory item.
\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6ea93329",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory(_redfishobj, inventory_uri):\n",
+ "\n",
+ " _members = _redfishobj.get(inventory_uri).obj['Members']\n",
+ " if not _members:\n",
+ " sys.stderr.write(\"\\tInventory empty.\\n\")\n",
+ " else:\n",
+ " for inventory_item in _members:\n",
+ " _resp = _redfishobj.get(inventory_item['@odata.id'])\n",
+ " sys.stdout.write(\"Printing contents of inventory item, \\'%s\\':\\'%s\\'\\n\" % (_resp.dict.get('Name'), _resp.dict.get('Description')))\n",
+ " print(json.dumps(_resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3c50b324",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. SELECT variable is by default set to 'firmware'. But one can choose either 'software' or 'firmware' for inventory selection.
\n",
+ " \n",
+ "6. Then we call get_inventory_uri with our redfish object and SELECT variable.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91f1a8a5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ccf0065",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " \n",
+ " SELECT = \"firmware\" #provide either 'software' or 'firmware' for inventory selection\n",
+ " \n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_inventory_uri(REDFISHOBJ, SELECT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb99bfc3",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Update_iLO_Firmware-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Update_iLO_Firmware-checkpoint.ipynb
new file mode 100644
index 0000000..4b36168
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Update_iLO_Firmware-checkpoint.ipynb
@@ -0,0 +1,260 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Update Firmware via HTTP URL
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1a50e99e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3af51f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c723fbdf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b42060d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our update_ilo_firmware function overview, in the end this will update the iLO Firmware.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The update_ilo_firmware function takes three parameters - _redfishobj representing the connection to the server, fw_url representing the firmware update URL, and tpm_flag representing the TPM override flag.\n",
+ "
\n",
+ " \n",
+ "2. The function initializes the body and update_service_uri variables to None.\n",
+ "
\n",
+ "\n",
+ "3. The get_resource_directory() function is called by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, the relevant URI is found by navigating through the server's API. If the resource directory is available, the relevant URI is found from the resource directory.\n",
+ "
\n",
+ "\n",
+ "4. If update_service_uri and fw_url are not None, the update_uri is retrieved from the server using the get() method and by accessing the Actions attribute.\n",
+ "
\n",
+ "\n",
+ "5. The body dictionary is updated with the fw_url and tpm_flag if tpm_flag is provided.\n",
+ "
\n",
+ "\n",
+ "6. The post() method is called on the update_uri with the body dictionary as a parameter. The response is stored in the resp variable.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, the iLO extended info error message is printed. If the HTTP response status code is not 200 or 201, an error message is printed. If the HTTP response status code is 200 or 201, a success message is printed along.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59bfcc8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def update_ilo_firmware(_redfishobj, fw_url, tpm_flag):\n",
+ "\n",
+ " body = dict()\n",
+ " update_service_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if update_service_uri and fw_url:\n",
+ " update_uri = _redfishobj.get(update_service_uri).obj['Actions']['#UpdateService.SimpleUpdate']['target']\n",
+ " body[\"ImageURI\"] = fw_url\n",
+ " if tpm_flag:\n",
+ " body[\"TPMOverrideFlag\"] = tpm_flag\n",
+ " resp = _redfishobj.post(update_uri, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bb9670c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to update the firmware.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call update_ilo_firmware with our redfish object, FIRMWARE_URL and Trusted Platform Module (TPM) Flag as parameters.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for Firmware URL, enter the firmware file path. Example: \"http://\">
\n",
+ " \n",
+ "8. If a TPM module (Trusted Platform Module / Cryptographic Co-processor) is installed/present onboard then be sure to include this by changing TPM_FLAG variable to True. By default this variable is set to False.
\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "82f44947",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "98301396",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # firmware file path and filename\n",
+ " FIRMWARE_URL = input(\"Enter Firmware URL\")\n",
+ " \n",
+ " # If a TPM module (Trusted Platform Module/ Cryptographic Co-processor) is installed/present\n",
+ " # onboard then be sure to include this.\n",
+ " \n",
+ " TPM_FLAG = False\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " update_ilo_firmware(REDFISHOBJ, FIRMWARE_URL, TPM_FLAG)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cce9c778",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_Firmware_iLO_Repository_with_COMPSIG.py-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_Firmware_iLO_Repository_with_COMPSIG.py-checkpoint.ipynb
new file mode 100644
index 0000000..3693313
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_Firmware_iLO_Repository_with_COMPSIG.py-checkpoint.ipynb
@@ -0,0 +1,287 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7fdda07e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware component and associated Component Signature (.comsig) file to iLO repository
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7574d95",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b1692ebb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0a03dc92",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ce6577f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware component along with compsig to the iLO Repository.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function takes four parameters: _redfishobj which is the Redfish client object, firmware_loc which is the path to the firmware image file, compsig_loc which is the path to the firmware image signature file, update_repo which is a boolean flag to specify whether to update the firmware repository or not, and update_target which is a boolean flag to specify whether to update the target device or not.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then the function retrieves the update service URI from the response of the previous step.\n",
+ "
\n",
+ "\n",
+ "4. The function reads the firmware and signature files and prepares the data in the required format to upload the firmware using the HttpPushUri. The function builds a list of tuples that contain the session key, json data, firmware file, and firmware signature file.\n",
+ "
\n",
+ "\n",
+ "5. The function creates a header dictionary containing the session key.\n",
+ "
\n",
+ "\n",
+ "6. The function passes the list of payload to the _redfishobj.post() method with the HttpPushUri as the path to upload the firmware and signature files.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, print an error message indicating that the firmware upload failed with the HTTP response message. If the HTTP response status code is neither 200 nor 201, print an error message indicating that an HTTP response with the status code was returned. If the HTTP response status code is 200 or 201, print a success message indicating that the firmware upload is complete.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "53612a22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, compsig_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " compsigname = os.path.basename(compsig_loc)\n",
+ " with open(compsig_loc, 'rb') as cle:\n",
+ " compsigoutput = cle.read()\n",
+ "\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ " compsig_tuple = ('compsig', (compsigname, compsigoutput, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(compsig_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware... Error: '%s'\\n\" % str(resp))\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "85b41e74",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for entering Firmware companent path, enter the entire path containing the firmware component.. Example: \"/path/to/cpxxxxxx.exe\"
The path to the firmware component file to upload. .rpm and .zip component are also valid.
\n",
+ " \n",
+ "8. When prompted for entering compsig path, enter the entire path containing the Component Signature (compsig) file having .compsig extension.. Example: \"/path/to//cpxxxxxx.compsig\"
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6ee4ac0a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17305248",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware component file to upload.\n",
+ " # .rpm and .zip component are also valid.\n",
+ " #\n",
+ " \n",
+ " FIRMWARE_PATH = input(\"Enter firmware path \")\n",
+ " COMPSIG_PATH = input(\"Enter compsig path \")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cacde035",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_firmware_to_iLO_repository-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_firmware_to_iLO_repository-checkpoint.ipynb
new file mode 100644
index 0000000..306e134
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/.ipynb_checkpoints/Upload_firmware_to_iLO_repository-checkpoint.ipynb
@@ -0,0 +1,276 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware to iLO repository for flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1ab478ee",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "183ac248",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7bede674",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b72b845",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware to the iLO Repository for flashing.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload the firmware.
\n",
+ "\n",
+ "1. The function takes these parameters as input: _redfishobj, firmware_loc, update_repo, and update_target.\n",
+ "
\n",
+ " \n",
+ "2. It calls the get_resource_directory() function by passing the _redfishobj parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, it obtains all account instances from the resource directory and then retrieves the URI for the Update Service.\n",
+ "
\n",
+ "\n",
+ "4. The function then sends an HTTP GET request to the obtained URI to retrieve the HttpPushUri path.\n",
+ "
\n",
+ "\n",
+ "5. It then reads the firmware file using the open() method and stores its contents in the output variable.\n",
+ "
\n",
+ "\n",
+ "6. The function builds the payload for the multipart-form data using session key, parameters, and firmware file tuples.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. It then creates a header dictionary containing the session key and passes the whole payload to the post() method.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "8. If the HTTP response status code is not 200 or 201, it prints an error message. If the HTTP response status code is 400, it prints a \"Failed to upload firmware...\" error message. If the HTTP response status code is 200 or 201, it prints a success message.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "beb01150",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4041fb30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted, enter the entire path containing the new firmware (.fwpkg). Example: \"C:\\\\Users\\\\oconnogr\\\\git\\\\python-restful-interface-tool\\\\src\\\\ilo5_230_p31.fwpkg\"\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dbfb1f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d3ff3bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware file to upload\n",
+ " FIRMWARE_PATH = input(\"Enter entire path containing the Firmware (.fwpkg)\")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6d44e9b",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Software_Firmware_Inventory.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Software_Firmware_Inventory.ipynb
new file mode 100644
index 0000000..f0253db
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Software_Firmware_Inventory.ipynb
@@ -0,0 +1,288 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "90595900",
+ "metadata": {},
+ "source": [
+ "Script for viewing the firmware inventory on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "887d7741",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "830d2b30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2a88487d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "827bf8e1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_inventory_uri function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function initializes the update_service_uri and inventory_uri variables to None.
\n",
+ " \n",
+ "2. Call the get_resource_directory() function by passing _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or disabled, find the relevant URI by navigating through the server's API.
\n",
+ "\n",
+ "3. If the resource directory is available, find the relevant URI from the resource directory.
\n",
+ "\n",
+ "4. Check if update_service_uri has been set. If update_service_uri is not None, retrieve the URI for the update service.
\n",
+ "\n",
+ "5. Retrieve the update service response using the get() method on _redfishobj. If the provided selection contains the word \"software\" (case insensitive), set the inventory_uri to the URI of the software inventory obtained from the update service response.
\n",
+ "\n",
+ "6. If the provided selection contains the word \"firmware\" (case insensitive), set the inventory_uri to the URI of the firmware inventory obtained from the update service response.
\n",
+ " \n",
+ "7. If an invalid selection is provided, raise an exception with an error message.
\n",
+ " \n",
+ "8. Print the inventory URI.
\n",
+ " \n",
+ "9. Call the get_inventory() function, passing _redfishobj and inventory_uri as parameters.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a11214ba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory_uri(_redfishobj, select):\n",
+ "\n",
+ " update_service_uri = None\n",
+ " inventory_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if update_service_uri:\n",
+ " update_service_resp = _redfishobj.get(update_service_uri)\n",
+ " if \"software\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['SoftwareInventory']['@odata.id']\n",
+ " elif \"firmware\" in select.lower():\n",
+ " inventory_uri = update_service_resp.obj['FirmwareInventory']['@odata.id']\n",
+ " else:\n",
+ " raise Exception(\"Invalid selection provided: Please select 'software' or 'firmware' to obtain the relevant invetory data.\")\n",
+ " sys.stdout.write(\"Printing data in invetory: %s\\n\" % inventory_uri)\n",
+ " get_inventory(_redfishobj, inventory_uri)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c329bc0f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is our get_inventory function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function retrieves the list of members from the provided inventory_uri using the get() method on _redfishobj.
\n",
+ " \n",
+ "2. If there are no members in the inventory, print a message indicating that the inventory is empty.
\n",
+ "\n",
+ "3. Iterate over each inventory item in the list of members.
\n",
+ "\n",
+ "4. Retrieve the details of each inventory item using the get() method on _redfishobj with the item's URI.
\n",
+ "\n",
+ "5. Print the name and description of the inventory item.
\n",
+ "\n",
+ "6. Print the JSON-formatted contents of the inventory item.
\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6ea93329",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_inventory(_redfishobj, inventory_uri):\n",
+ "\n",
+ " _members = _redfishobj.get(inventory_uri).obj['Members']\n",
+ " if not _members:\n",
+ " sys.stderr.write(\"\\tInventory empty.\\n\")\n",
+ " else:\n",
+ " for inventory_item in _members:\n",
+ " _resp = _redfishobj.get(inventory_item['@odata.id'])\n",
+ " sys.stdout.write(\"Printing contents of inventory item, \\'%s\\':\\'%s\\'\\n\" % (_resp.dict.get('Name'), _resp.dict.get('Description')))\n",
+ " print(json.dumps(_resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3c50b324",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. SELECT variable is by default set to 'firmware'. But one can choose either 'software' or 'firmware' for inventory selection.
\n",
+ " \n",
+ "6. Then we call get_inventory_uri with our redfish object and SELECT variable.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "91f1a8a5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ccf0065",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " \n",
+ " SELECT = \"firmware\" #provide either 'software' or 'firmware' for inventory selection\n",
+ " \n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_inventory_uri(REDFISHOBJ, SELECT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb99bfc3",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Update_iLO_Firmware.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Update_iLO_Firmware.ipynb
new file mode 100644
index 0000000..4b36168
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Update_iLO_Firmware.ipynb
@@ -0,0 +1,260 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Update Firmware via HTTP URL
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1a50e99e",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3af51f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c723fbdf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b42060d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our update_ilo_firmware function overview, in the end this will update the iLO Firmware.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The update_ilo_firmware function takes three parameters - _redfishobj representing the connection to the server, fw_url representing the firmware update URL, and tpm_flag representing the TPM override flag.\n",
+ "
\n",
+ " \n",
+ "2. The function initializes the body and update_service_uri variables to None.\n",
+ "
\n",
+ "\n",
+ "3. The get_resource_directory() function is called by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, the relevant URI is found by navigating through the server's API. If the resource directory is available, the relevant URI is found from the resource directory.\n",
+ "
\n",
+ "\n",
+ "4. If update_service_uri and fw_url are not None, the update_uri is retrieved from the server using the get() method and by accessing the Actions attribute.\n",
+ "
\n",
+ "\n",
+ "5. The body dictionary is updated with the fw_url and tpm_flag if tpm_flag is provided.\n",
+ "
\n",
+ "\n",
+ "6. The post() method is called on the update_uri with the body dictionary as a parameter. The response is stored in the resp variable.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, the iLO extended info error message is printed. If the HTTP response status code is not 200 or 201, an error message is printed. If the HTTP response status code is 200 or 201, a success message is printed along.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "59bfcc8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def update_ilo_firmware(_redfishobj, fw_url, tpm_flag):\n",
+ "\n",
+ " body = dict()\n",
+ " update_service_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if update_service_uri and fw_url:\n",
+ " update_uri = _redfishobj.get(update_service_uri).obj['Actions']['#UpdateService.SimpleUpdate']['target']\n",
+ " body[\"ImageURI\"] = fw_url\n",
+ " if tpm_flag:\n",
+ " body[\"TPMOverrideFlag\"] = tpm_flag\n",
+ " resp = _redfishobj.post(update_uri, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bb9670c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to update the firmware.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call update_ilo_firmware with our redfish object, FIRMWARE_URL and Trusted Platform Module (TPM) Flag as parameters.
\n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for Firmware URL, enter the firmware file path. Example: \"http://\">
\n",
+ " \n",
+ "8. If a TPM module (Trusted Platform Module / Cryptographic Co-processor) is installed/present onboard then be sure to include this by changing TPM_FLAG variable to True. By default this variable is set to False.
\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "82f44947",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "98301396",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # firmware file path and filename\n",
+ " FIRMWARE_URL = input(\"Enter Firmware URL\")\n",
+ " \n",
+ " # If a TPM module (Trusted Platform Module/ Cryptographic Co-processor) is installed/present\n",
+ " # onboard then be sure to include this.\n",
+ " \n",
+ " TPM_FLAG = False\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " update_ilo_firmware(REDFISHOBJ, FIRMWARE_URL, TPM_FLAG)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cce9c778",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_Firmware_iLO_Repository_with_COMPSIG.py.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_Firmware_iLO_Repository_with_COMPSIG.py.ipynb
new file mode 100644
index 0000000..3693313
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_Firmware_iLO_Repository_with_COMPSIG.py.ipynb
@@ -0,0 +1,287 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7fdda07e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware component and associated Component Signature (.comsig) file to iLO repository
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7574d95",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b1692ebb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0a03dc92",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "#This is to take passwords as input securely\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ce6577f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware component along with compsig to the iLO Repository.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. This function takes four parameters: _redfishobj which is the Redfish client object, firmware_loc which is the path to the firmware image file, compsig_loc which is the path to the firmware image signature file, update_repo which is a boolean flag to specify whether to update the firmware repository or not, and update_target which is a boolean flag to specify whether to update the target device or not.\n",
+ "
\n",
+ " \n",
+ "2. Call get_resource_directory() function by passing the _redfishobj as a parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, find the relevant URI by navigating through the server's API. If the resource directory is available, find the relevant URI from the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. Then the function retrieves the update service URI from the response of the previous step.\n",
+ "
\n",
+ "\n",
+ "4. The function reads the firmware and signature files and prepares the data in the required format to upload the firmware using the HttpPushUri. The function builds a list of tuples that contain the session key, json data, firmware file, and firmware signature file.\n",
+ "
\n",
+ "\n",
+ "5. The function creates a header dictionary containing the session key.\n",
+ "
\n",
+ "\n",
+ "6. The function passes the list of payload to the _redfishobj.post() method with the HttpPushUri as the path to upload the firmware and signature files.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. If the HTTP response status code is 400, print an error message indicating that the firmware upload failed with the HTTP response message. If the HTTP response status code is neither 200 nor 201, print an error message indicating that an HTTP response with the status code was returned. If the HTTP response status code is 200 or 201, print a success message indicating that the firmware upload is complete.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "53612a22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, compsig_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " compsigname = os.path.basename(compsig_loc)\n",
+ " with open(compsig_loc, 'rb') as cle:\n",
+ " compsigoutput = cle.read()\n",
+ "\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ " compsig_tuple = ('compsig', (compsigname, compsigoutput, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(compsig_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware... Error: '%s'\\n\" % str(resp))\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "85b41e74",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted for entering Firmware companent path, enter the entire path containing the firmware component.. Example: \"/path/to/cpxxxxxx.exe\"
The path to the firmware component file to upload. .rpm and .zip component are also valid.
\n",
+ " \n",
+ "8. When prompted for entering compsig path, enter the entire path containing the Component Signature (compsig) file having .compsig extension.. Example: \"/path/to//cpxxxxxx.compsig\"
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6ee4ac0a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17305248",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware component file to upload.\n",
+ " # .rpm and .zip component are also valid.\n",
+ " #\n",
+ " \n",
+ " FIRMWARE_PATH = input(\"Enter firmware path \")\n",
+ " COMPSIG_PATH = input(\"Enter compsig path \")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, COMPSIG_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cacde035",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_firmware_to_iLO_repository.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_firmware_to_iLO_repository.ipynb
new file mode 100644
index 0000000..306e134
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/FIRMWARE/Upload_firmware_to_iLO_repository.ipynb
@@ -0,0 +1,276 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fb9e0a5e",
+ "metadata": {},
+ "source": [
+ "Upload Firmware to iLO repository for flashing
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1ab478ee",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "183ac248",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7bede674",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b72b845",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our upload_firmware function overview, in the end this will upload firmware to the iLO Repository for flashing.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload the firmware.
\n",
+ "\n",
+ "1. The function takes these parameters as input: _redfishobj, firmware_loc, update_repo, and update_target.\n",
+ "
\n",
+ " \n",
+ "2. It calls the get_resource_directory() function by passing the _redfishobj parameter to retrieve the resource directory of the server. If the resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, it obtains all account instances from the resource directory and then retrieves the URI for the Update Service.\n",
+ "
\n",
+ "\n",
+ "4. The function then sends an HTTP GET request to the obtained URI to retrieve the HttpPushUri path.\n",
+ "
\n",
+ "\n",
+ "5. It then reads the firmware file using the open() method and stores its contents in the output variable.\n",
+ "
\n",
+ "\n",
+ "6. The function builds the payload for the multipart-form data using session key, parameters, and firmware file tuples.\n",
+ "
\n",
+ "\n",
+ "\n",
+ "7. It then creates a header dictionary containing the session key and passes the whole payload to the post() method.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "8. If the HTTP response status code is not 200 or 201, it prints an error message. If the HTTP response status code is 400, it prints a \"Failed to upload firmware...\" error message. If the HTTP response status code is 200 or 201, it prints a success message.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "beb01150",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def upload_firmware(_redfishobj, firmware_loc, update_repo=True, update_target=False):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually\n",
+ " update_service_uri = _redfishobj.root.obj['UpdateService']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#UpdateService.' in instance['@odata.type']:\n",
+ " update_service_uri = instance['@odata.id']\n",
+ "\n",
+ " update_service_response = _redfishobj.get(update_service_uri)\n",
+ "\n",
+ " path = update_service_response.obj.HttpPushUri\n",
+ "\n",
+ " body = []\n",
+ " json_data = {'UpdateRepository': update_repo, 'UpdateTarget': update_target, 'ETag': 'atag', 'Section': 0}\n",
+ " session_key = _redfishobj.session_key\n",
+ "\n",
+ " filename = os.path.basename(firmware_loc)\n",
+ " with open(firmware_loc, 'rb') as fle:\n",
+ " output = fle.read()\n",
+ "\n",
+ " session_tuple = ('sessionKey', session_key)\n",
+ " parameters_tuple = ('parameters', json.dumps(json_data))\n",
+ " file_tuple = ('file', (filename, output, 'application/octet-stream'))\n",
+ "\n",
+ " #Build the payload from each multipart-form data tuple\n",
+ " body.append(session_tuple)\n",
+ " body.append(parameters_tuple)\n",
+ " body.append(file_tuple)\n",
+ "\n",
+ " #Create our header dictionary\n",
+ " header = {'Cookie': 'sessionKey=' + session_key}\n",
+ "\n",
+ " #We pass the whole list payload to post\n",
+ " resp = _redfishobj.post(path, body, headers=header)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " sys.stderr.write(\"Failed to upload firmware...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Upload complete!\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4041fb30",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to upload new firmware to iLO repository for flashing.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call upload_firmware with our redfish object, FIRMWARE_PATH, UPDATE_REPO (set as True) and UPDATE_TARGET (set as False) as parameters.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ " \n",
+ "7. When prompted, enter the entire path containing the new firmware (.fwpkg). Example: \"C:\\\\Users\\\\oconnogr\\\\git\\\\python-restful-interface-tool\\\\src\\\\ilo5_230_p31.fwpkg\"\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dbfb1f99",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d3ff3bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " # The path to the firmware file to upload\n",
+ " FIRMWARE_PATH = input(\"Enter entire path containing the Firmware (.fwpkg)\")\n",
+ " # Upload the firmware file to the iLO Repository\n",
+ " UPDATE_REPO = True\n",
+ " # Update the system with the firmware file\n",
+ " UPDATE_TARGET = False\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " upload_firmware(REDFISHOBJ, FIRMWARE_PATH, UPDATE_REPO, UPDATE_TARGET)\n",
+ "\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6d44e9b",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/.ipynb_checkpoints/Expand_data-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/.ipynb_checkpoints/Expand_data-checkpoint.ipynb
new file mode 100644
index 0000000..d0fd0df
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/.ipynb_checkpoints/Expand_data-checkpoint.ipynb
@@ -0,0 +1,216 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b6480262",
+ "metadata": {},
+ "source": [
+ "Example of expanding data responses
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "051ce734",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58eab40d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cfa6671a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5f4583b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our expand_data function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The expand_data function takes two parameters: _redfishobj and expand_url, with a default value of \"/redfish/v1/\" for expand_url.
\n",
+ " \n",
+ "2. It sends a GET request to the _redfishobj (Redfish object) using the provided expand_url to retrieve the response.
\n",
+ "\n",
+ "3. Another GET request is sent to the _redfishobj with the expand_url appended with ?$expand=.. This request is used to retrieve an expanded response.
\n",
+ "\n",
+ "4. The function then prints the standard response to the standard output stream.
\n",
+ "\n",
+ "5. The standard response, represented as a dictionary, is printed.
\n",
+ "\n",
+ "6. Next, the function prints the expanded response to the standard output stream.
\n",
+ " \n",
+ "7. The expanded response, represented as a dictionary, is printed.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "509e8725",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def expand_data(_redfishobj, expand_url=\"/redfish/v1/\"):\n",
+ "\n",
+ " response = _redfishobj.get(expand_url)\n",
+ " exp_response = _redfishobj.get(expand_url+'?$expand=.')\n",
+ " sys.stdout.write('Standard response:\\n')\n",
+ " sys.stdout.write('\\t'+str(response.dict)+'\\n')\n",
+ " sys.stdout.write('Expanded response:\\n')\n",
+ " sys.stdout.write('\\t'+str(exp_response.dict)+'\\n')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "523f5bda",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. When prompted for URL, enter the URL that you want to be expanded. Example: /redfish/v1/systems/
\n",
+ " \n",
+ "6. Then we call expand_data with our redfish object and EXPAND_URL.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b80bdfed",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "eabae678",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #url to be expanded\n",
+ " EXPAND_URL = input(\"Enter the URL that is to be expanded (Ex: /redfish/v1/systems/)\")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " expand_data(REDFISHOBJ, EXPAND_URL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76b99be7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/Expand_data.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/Expand_data.ipynb
new file mode 100644
index 0000000..d0fd0df
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/MISCELLANEOUS/Expand_data.ipynb
@@ -0,0 +1,216 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b6480262",
+ "metadata": {},
+ "source": [
+ "Example of expanding data responses
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "051ce734",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58eab40d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cfa6671a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5f4583b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our expand_data function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The expand_data function takes two parameters: _redfishobj and expand_url, with a default value of \"/redfish/v1/\" for expand_url.
\n",
+ " \n",
+ "2. It sends a GET request to the _redfishobj (Redfish object) using the provided expand_url to retrieve the response.
\n",
+ "\n",
+ "3. Another GET request is sent to the _redfishobj with the expand_url appended with ?$expand=.. This request is used to retrieve an expanded response.
\n",
+ "\n",
+ "4. The function then prints the standard response to the standard output stream.
\n",
+ "\n",
+ "5. The standard response, represented as a dictionary, is printed.
\n",
+ "\n",
+ "6. Next, the function prints the expanded response to the standard output stream.
\n",
+ " \n",
+ "7. The expanded response, represented as a dictionary, is printed.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "509e8725",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def expand_data(_redfishobj, expand_url=\"/redfish/v1/\"):\n",
+ "\n",
+ " response = _redfishobj.get(expand_url)\n",
+ " exp_response = _redfishobj.get(expand_url+'?$expand=.')\n",
+ " sys.stdout.write('Standard response:\\n')\n",
+ " sys.stdout.write('\\t'+str(response.dict)+'\\n')\n",
+ " sys.stdout.write('Expanded response:\\n')\n",
+ " sys.stdout.write('\\t'+str(exp_response.dict)+'\\n')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "523f5bda",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. When prompted for URL, enter the URL that you want to be expanded. Example: /redfish/v1/systems/
\n",
+ " \n",
+ "6. Then we call expand_data with our redfish object and EXPAND_URL.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b80bdfed",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "eabae678",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #url to be expanded\n",
+ " EXPAND_URL = input(\"Enter the URL that is to be expanded (Ex: /redfish/v1/systems/)\")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " expand_data(REDFISHOBJ, EXPAND_URL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76b99be7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb
new file mode 100644
index 0000000..073e74b
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb
@@ -0,0 +1,268 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'redfish'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32mC:\\Users\\BHUVAN~1\\AppData\\Local\\Temp/ipykernel_25992/2798673744.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mjson\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mRedfishClient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'redfish'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/Get_Powermetrics_Average.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/Get_Powermetrics_Average.ipynb
new file mode 100644
index 0000000..073e74b
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/POWER/Get_Powermetrics_Average.ipynb
@@ -0,0 +1,268 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'redfish'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32mC:\\Users\\BHUVAN~1\\AppData\\Local\\Temp/ipykernel_25992/2798673744.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mjson\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mRedfishClient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'redfish'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/.ipynb_checkpoints/Add_user_account-checkpoint.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/.ipynb_checkpoints/Add_user_account-checkpoint.ipynb
new file mode 100644
index 0000000..84a87c0
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/.ipynb_checkpoints/Add_user_account-checkpoint.ipynb
@@ -0,0 +1,507 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Add new user account by iLO privileges or redfish standard roles
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "613446a1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our add_ilo_user_account function overview, in the end this will add new iLO user account. This function will be called only if the generation of iLO is not 4.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new iLO user account.
\n",
+ "\n",
+ "1. This function takes in six parameters: _redfishobj, new_loginname, new_username, new_password, role_id, and privilege_dict.\n",
+ "
\n",
+ " \n",
+ "2. The function first calls the get_resource_directory() function by passing _redfishobj as the parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, the function obtains all the account instances from the resource directory and sets the account_collection_uri. If it's an HPE server, it sets the body dictionary with the privileges passed in privilege_dict parameter.\n",
+ "
\n",
+ "\n",
+ "4. The function then fills the body dictionary with the necessary details like new_username, new_password, and RoleId/Oem depending on the type of server.\n",
+ "
\n",
+ "\n",
+ "5. The function then sends a POST command by passing the account_collection_uri and body dictionary as the parameters to create a new user account.\n",
+ "
\n",
+ "\n",
+ "6. If the iLO server responds with an HTTP status code outside of 200 or 201, the function prints an error message. If the HTTP response status code is 400, it prints the iLO extended info error message. If the HTTP response status code is 200 or 201, it prints a success message and the newly created user account details in JSON format.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea197a20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account(_redfishobj, new_loginname, new_username, new_password, role_id, privilege_dict):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #Add via role id\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " #HPE server, so add via privileges\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " #Add login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " #Fill in the rest of the payload\n",
+ " body[\"UserName\"] = new_username\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "94f279a6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This function adds a new iLO user account in the HPE Gen9 server or having iLO generation 4 servers.
\n",
+ " \n",
+ " \n",
+ "1. The function takes _redfishobj, new_loginname, new_username, and new_password as input parameters..\n",
+ "
\n",
+ " \n",
+ "2. The account collection URI for the HPE Gen9 server is initialized as /redfish/v1/AccountService/Accounts/.\n",
+ "
\n",
+ "\n",
+ "3. The privilege dictionary for the HPE Gen9 server is constructed in the body variable. The privileges are specified for the iLO user account to be added. The login name is also added.\n",
+ "
\n",
+ "\n",
+ "4. The username and password for the iLO user account to be added are added to the body dictionary.\n",
+ "
\n",
+ "\n",
+ "5. The POST command is passed to _redfishobj to add the iLO user account using the account_collection_uri and body dictionary.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is 200 or 201, the newly created user account details are printed using json.dumps().\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If the HTTP response status code is not 200 or 201, an error message is printed using sys.stderr.write().\n",
+ " \n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bc44c03c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account_gen9(_redfishobj, new_loginname, new_username, new_password):\n",
+ "\n",
+ " account_collection_uri = \"/redfish/v1/AccountService/Accounts/\"\n",
+ " #Add via gen9 priv dic\n",
+ " body = {'Oem': {'Hp': {'Privileges': {\"LoginPriv\": True, \"RemoteConsolePriv\": True,\n",
+ " \"UserConfigPriv\": True, \"VirtualMediaPriv\": True, \"VirtualPowerAndResetPriv\": True,\n",
+ " \"iLOConfigPriv\": True}, 'LoginName': new_loginname}},'UserName': new_username, 'Password': new_password}\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new user.\n",
+ " \n",
+ "\n",
+ " 1. The follwoing Main function prompts to take SYSTEM_URL, LOGIN_ACCOUNT, LOGIN_PASSWORD, ACCOUNT_LOGIN_NAME, ACCOUNT_USER_NAME, ACCOUNT_PASSWORD, ROLE_ID and PRIVILAGES as inputs.
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " 2. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ " 3. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object. If users want to use create RedfishClient using \"certificate\" for authentication (which is optional), they can do so by uncommenting the lines ca_cert_data, ca_cert_data, ca_cert_data,ca_cert_data and providing their values.
\n",
+ "
\n",
+ " \n",
+ " 4. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ " \n",
+ " 5. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " 6. Then we call add_ilo_user_account or add_ilo_user_account_gen9 based on the generation of iLO by pssing appropriate as parameters to those functions.
\n",
+ " \n",
+ " \n",
+ " 7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally, use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39d4c0f0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Roles and Privileges
\n",
+ "
iLO uses a set of privileges assigned to each user account to grant and restrict access to features. iLO 6’s privileges are:
\n",
+ " \n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Redfish | \n",
+ " iLO Web Interface (GUI) | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv | \n",
+ " Login | \n",
+ "
\n",
+ " \n",
+ " | RemoteConsolePriv | \n",
+ " Remote Console | \n",
+ "
\n",
+ " \n",
+ " | VirtualPowerAndResetPriv | \n",
+ " Virtual Power and Reset | \n",
+ "
\n",
+ " \n",
+ " | VirtualMediaPriv | \n",
+ " Virtual Media | \n",
+ "
\n",
+ " \n",
+ " | HostBIOSConfigPriv | \n",
+ " Host BIOS | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv | \n",
+ " Configure iLO Settings | \n",
+ "
\n",
+ " \n",
+ " | UserConfigPriv | \n",
+ " Administer User Accounts | \n",
+ "
\n",
+ " \n",
+ " | HostNICConfigPriv | \n",
+ " Host NIC | \n",
+ "
\n",
+ " \n",
+ " | HostStorageConfigPriv | \n",
+ " Host Storage | \n",
+ "
\n",
+ " \n",
+ " | SystemRecoveryConfigPriv | \n",
+ " Recovery Set | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
Roles
\n",
+ "
You can use RoleId to create users with specific starting privileges.
\n",
+ "On a GET of the local user account, RoleId is synthesized based upon the enabled privileges. iLO 6 does not store a separate RoleId value. For this reason, modifications to raw privileges may or may not result in a changed RoleId based upon iLO’s mapping.
\n",
+ "If the PATCH includes both RoleID and individual privileges, the privileges corresponding to the RoleId are assigned to the local user account first, and then the explicit privileges are assigned.
\n",
+ "\n",
+ "
Privileges granted on Local Account Creation by RoleId
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | RoleId | \n",
+ " Privileges | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Administrator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, UserConfigPriv, VirtualMediaPriv, VirtualPowerAndResetPriv, iLOConfigPriv | \n",
+ "
\n",
+ " \n",
+ " | Operator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, VirtualMediaPriv, VirtualPowerAndResetPriv | \n",
+ "
\n",
+ " \n",
+ " | ReadOnly | \n",
+ " LoginPriv | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "
RoleId shown on an existing Local User Account by Privilege
\n",
+ "
The RoleId reported is the smallest superset of assigned privileges.
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Privileges | \n",
+ " RoleId | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv only | \n",
+ " ReadOnly | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv or UserConfigPriv or SystemRecoveryConfigPriv and anything else | \n",
+ " Administrator | \n",
+ "
\n",
+ " \n",
+ " | any other combination | \n",
+ " Operator | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ " \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b99181a4",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #account login name (iLO GUI actually considers this to be 'UserName', but\n",
+ " #this is the redfish standard username)\n",
+ " ACCOUNT_LOGIN_NAME = input(\"Enter Account Login Name: \")\n",
+ "\n",
+ " #account user name (iLO GUI actually considers this to be 'LoginName', but\n",
+ " #this is the redfish login)\n",
+ " ACCOUNT_USER_NAME = input(\"Enter Account User Name: \")\n",
+ "\n",
+ " #account password\n",
+ " ACCOUNT_PASSWORD = getpass.getpass(\"Enter Account password: \")\n",
+ "\n",
+ " #A predefined role for the user, (The redfish standard method for accounts).\n",
+ " #This is a translated to a pre-configured arrangement of privileges on HPE servers\n",
+ " ROLE_ID = input(\"Enter ROLE_ID: \") #Administrator, ReadOnly or Operator are available\n",
+ "\n",
+ " #Dictionary of modifiable privileges for HPE servers (modify this if you wish to directly set\n",
+ " #an account with specific privileges\n",
+ " \n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": True, \"VirtualMediaPriv\": True, \"RemoteConsolePriv\": True, \"UserConfigPriv\": True, \"VirtualPowerAndResetPriv\": True, \\\n",
+ " \"SystemRecoveryConfigPriv\": True, \"LoginPriv\": True, \"HostStorageConfigPriv\": True, \"HostNICConfigPriv\": True,\n",
+ " \"HostBIOSConfigPriv\": True}\n",
+ " \n",
+ " print(\"For the below privilages enter 'True' if that privilages needs to be set for the user else enter 'False'\")\n",
+ " \n",
+ " for key in PRIVILEGE_DICT.keys():\n",
+ " PRIVILEGE_DICT[key] = input(f\"{key}\")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ "# ca_cert_data = {}\n",
+ "# ca_cert_data[\"cert_file\"] = \"c:\\\\test\\\\ppcacuser.crt\"\n",
+ "# ca_cert_data[\"key_file\"] = \"c:\\\\test\\\\ppcacuserpriv.key\"\n",
+ "# ca_cert_data[\"key_password\"] = \"password\"\n",
+ " LOGIN_ACCOUNT = None\n",
+ " LOGIN_PASSWORD = None\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD, ca_cert_data=ca_cert_data)\n",
+ " #REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, ca_cert_data=ca_cert_data)\n",
+ " # Login with the Redfish client\n",
+ " if ca_cert_data is None:\n",
+ " REDFISHOBJ.login()\n",
+ " else:\n",
+ " REDFISHOBJ.login(auth='certificate')\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ "\n",
+ " #if account_collection_uri and accounts:\n",
+ " #add specified account\n",
+ " (ilogen,_) = get_gen(REDFISHOBJ)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) !=4:\n",
+ " add_ilo_user_account(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD,ROLE_ID,PRIVILEGE_DICT)\n",
+ " else:\n",
+ " add_ilo_user_account_gen9(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD)\n",
+ " \n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acf871b9",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/Add_user_account.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/Add_user_account.ipynb
new file mode 100644
index 0000000..84a87c0
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/USERS/Add_user_account.ipynb
@@ -0,0 +1,507 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "f815c9a7",
+ "metadata": {},
+ "source": [
+ "Add new user account by iLO privileges or redfish standard roles
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a3a9755",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc555954",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cff3ead6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "613446a1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our add_ilo_user_account function overview, in the end this will add new iLO user account. This function will be called only if the generation of iLO is not 4.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new iLO user account.
\n",
+ "\n",
+ "1. This function takes in six parameters: _redfishobj, new_loginname, new_username, new_password, role_id, and privilege_dict.\n",
+ "
\n",
+ " \n",
+ "2. The function first calls the get_resource_directory() function by passing _redfishobj as the parameter to retrieve the resource directory of the server. If resource directory is not available or it is disabled, it finds the relevant URI by navigating through the server's API.\n",
+ "
\n",
+ "\n",
+ "3. If the resource directory is available, the function obtains all the account instances from the resource directory and sets the account_collection_uri. If it's an HPE server, it sets the body dictionary with the privileges passed in privilege_dict parameter.\n",
+ "
\n",
+ "\n",
+ "4. The function then fills the body dictionary with the necessary details like new_username, new_password, and RoleId/Oem depending on the type of server.\n",
+ "
\n",
+ "\n",
+ "5. The function then sends a POST command by passing the account_collection_uri and body dictionary as the parameters to create a new user account.\n",
+ "
\n",
+ "\n",
+ "6. If the iLO server responds with an HTTP status code outside of 200 or 201, the function prints an error message. If the HTTP response status code is 400, it prints the iLO extended info error message. If the HTTP response status code is 200 or 201, it prints a success message and the newly created user account details in JSON format.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If bios_boot_uri is None, print an error message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea197a20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account(_redfishobj, new_loginname, new_username, new_password, role_id, privilege_dict):\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #Add via role id\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " #HPE server, so add via privileges\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " #Add login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " #Fill in the rest of the payload\n",
+ " body[\"UserName\"] = new_username\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message Info...\")\n",
+ " elif not resp.status in [200, 201]:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "94f279a6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This function adds a new iLO user account in the HPE Gen9 server or having iLO generation 4 servers.
\n",
+ " \n",
+ " \n",
+ "1. The function takes _redfishobj, new_loginname, new_username, and new_password as input parameters..\n",
+ "
\n",
+ " \n",
+ "2. The account collection URI for the HPE Gen9 server is initialized as /redfish/v1/AccountService/Accounts/.\n",
+ "
\n",
+ "\n",
+ "3. The privilege dictionary for the HPE Gen9 server is constructed in the body variable. The privileges are specified for the iLO user account to be added. The login name is also added.\n",
+ "
\n",
+ "\n",
+ "4. The username and password for the iLO user account to be added are added to the body dictionary.\n",
+ "
\n",
+ "\n",
+ "5. The POST command is passed to _redfishobj to add the iLO user account using the account_collection_uri and body dictionary.\n",
+ "
\n",
+ "\n",
+ "6. If the HTTP response status code is 200 or 201, the newly created user account details are printed using json.dumps().\n",
+ " \n",
+ "
\n",
+ "\n",
+ "7. If the HTTP response status code is not 200 or 201, an error message is printed using sys.stderr.write().\n",
+ " \n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bc44c03c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def add_ilo_user_account_gen9(_redfishobj, new_loginname, new_username, new_password):\n",
+ "\n",
+ " account_collection_uri = \"/redfish/v1/AccountService/Accounts/\"\n",
+ " #Add via gen9 priv dic\n",
+ " body = {'Oem': {'Hp': {'Privileges': {\"LoginPriv\": True, \"RemoteConsolePriv\": True,\n",
+ " \"UserConfigPriv\": True, \"VirtualMediaPriv\": True, \"VirtualPowerAndResetPriv\": True,\n",
+ " \"iLOConfigPriv\": True}, 'LoginName': new_loginname}},'UserName': new_username, 'Password': new_password}\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(account_collection_uri, body)\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b41f56eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to add new user.\n",
+ " \n",
+ "\n",
+ " 1. The follwoing Main function prompts to take SYSTEM_URL, LOGIN_ACCOUNT, LOGIN_PASSWORD, ACCOUNT_LOGIN_NAME, ACCOUNT_USER_NAME, ACCOUNT_PASSWORD, ROLE_ID and PRIVILAGES as inputs.
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " 2. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ " 3. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object. If users want to use create RedfishClient using \"certificate\" for authentication (which is optional), they can do so by uncommenting the lines ca_cert_data, ca_cert_data, ca_cert_data,ca_cert_data and providing their values.
\n",
+ "
\n",
+ " \n",
+ " 4. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ " \n",
+ " 5. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " 6. Then we call add_ilo_user_account or add_ilo_user_account_gen9 based on the generation of iLO by pssing appropriate as parameters to those functions.
\n",
+ " \n",
+ " \n",
+ " 7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ " \n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8cd2ffd",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally, use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "77edbde3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Instructions
\n",
+ "
\n",
+ " - When prompted for ACCOUNT_LOGIN_NAME, enter redfish standard username here as iLO GUI actually considers this to be 'UserName'
\n",
+ " - When prompted for ACCOUNT_USER_NAME, enter redfish login here iLO GUI actually considers this to be 'LoginName'
\n",
+ " - Role_ID: It is a predefined role for the user which can take \"Administrator\" or \"ReadOnly\" or \"Operator\" as input. For more informaion on roles and privilages refere the table in the next cell.
\n",
+ " - For more clarification on the above points please visit iLO Users Documentation
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39d4c0f0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Roles and Privileges
\n",
+ "
iLO uses a set of privileges assigned to each user account to grant and restrict access to features. iLO 6’s privileges are:
\n",
+ " \n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Redfish | \n",
+ " iLO Web Interface (GUI) | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv | \n",
+ " Login | \n",
+ "
\n",
+ " \n",
+ " | RemoteConsolePriv | \n",
+ " Remote Console | \n",
+ "
\n",
+ " \n",
+ " | VirtualPowerAndResetPriv | \n",
+ " Virtual Power and Reset | \n",
+ "
\n",
+ " \n",
+ " | VirtualMediaPriv | \n",
+ " Virtual Media | \n",
+ "
\n",
+ " \n",
+ " | HostBIOSConfigPriv | \n",
+ " Host BIOS | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv | \n",
+ " Configure iLO Settings | \n",
+ "
\n",
+ " \n",
+ " | UserConfigPriv | \n",
+ " Administer User Accounts | \n",
+ "
\n",
+ " \n",
+ " | HostNICConfigPriv | \n",
+ " Host NIC | \n",
+ "
\n",
+ " \n",
+ " | HostStorageConfigPriv | \n",
+ " Host Storage | \n",
+ "
\n",
+ " \n",
+ " | SystemRecoveryConfigPriv | \n",
+ " Recovery Set | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
Roles
\n",
+ "
You can use RoleId to create users with specific starting privileges.
\n",
+ "On a GET of the local user account, RoleId is synthesized based upon the enabled privileges. iLO 6 does not store a separate RoleId value. For this reason, modifications to raw privileges may or may not result in a changed RoleId based upon iLO’s mapping.
\n",
+ "If the PATCH includes both RoleID and individual privileges, the privileges corresponding to the RoleId are assigned to the local user account first, and then the explicit privileges are assigned.
\n",
+ "\n",
+ "
Privileges granted on Local Account Creation by RoleId
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | RoleId | \n",
+ " Privileges | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Administrator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, UserConfigPriv, VirtualMediaPriv, VirtualPowerAndResetPriv, iLOConfigPriv | \n",
+ "
\n",
+ " \n",
+ " | Operator | \n",
+ " HostBIOSConfigPriv, HostNICConfigPriv, HostStorageConfigPriv, LoginPriv, RemoteConsolePriv, VirtualMediaPriv, VirtualPowerAndResetPriv | \n",
+ "
\n",
+ " \n",
+ " | ReadOnly | \n",
+ " LoginPriv | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "
RoleId shown on an existing Local User Account by Privilege
\n",
+ "
The RoleId reported is the smallest superset of assigned privileges.
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | Privileges | \n",
+ " RoleId | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | LoginPriv only | \n",
+ " ReadOnly | \n",
+ "
\n",
+ " \n",
+ " | iLOConfigPriv or UserConfigPriv or SystemRecoveryConfigPriv and anything else | \n",
+ " Administrator | \n",
+ "
\n",
+ " \n",
+ " | any other combination | \n",
+ " Operator | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ " \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b99181a4",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Login account: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter your password: \")\n",
+ "\n",
+ " #account login name (iLO GUI actually considers this to be 'UserName', but\n",
+ " #this is the redfish standard username)\n",
+ " ACCOUNT_LOGIN_NAME = input(\"Enter Account Login Name: \")\n",
+ "\n",
+ " #account user name (iLO GUI actually considers this to be 'LoginName', but\n",
+ " #this is the redfish login)\n",
+ " ACCOUNT_USER_NAME = input(\"Enter Account User Name: \")\n",
+ "\n",
+ " #account password\n",
+ " ACCOUNT_PASSWORD = getpass.getpass(\"Enter Account password: \")\n",
+ "\n",
+ " #A predefined role for the user, (The redfish standard method for accounts).\n",
+ " #This is a translated to a pre-configured arrangement of privileges on HPE servers\n",
+ " ROLE_ID = input(\"Enter ROLE_ID: \") #Administrator, ReadOnly or Operator are available\n",
+ "\n",
+ " #Dictionary of modifiable privileges for HPE servers (modify this if you wish to directly set\n",
+ " #an account with specific privileges\n",
+ " \n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": True, \"VirtualMediaPriv\": True, \"RemoteConsolePriv\": True, \"UserConfigPriv\": True, \"VirtualPowerAndResetPriv\": True, \\\n",
+ " \"SystemRecoveryConfigPriv\": True, \"LoginPriv\": True, \"HostStorageConfigPriv\": True, \"HostNICConfigPriv\": True,\n",
+ " \"HostBIOSConfigPriv\": True}\n",
+ " \n",
+ " print(\"For the below privilages enter 'True' if that privilages needs to be set for the user else enter 'False'\")\n",
+ " \n",
+ " for key in PRIVILEGE_DICT.keys():\n",
+ " PRIVILEGE_DICT[key] = input(f\"{key}\")\n",
+ " \n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ "# ca_cert_data = {}\n",
+ "# ca_cert_data[\"cert_file\"] = \"c:\\\\test\\\\ppcacuser.crt\"\n",
+ "# ca_cert_data[\"key_file\"] = \"c:\\\\test\\\\ppcacuserpriv.key\"\n",
+ "# ca_cert_data[\"key_password\"] = \"password\"\n",
+ " LOGIN_ACCOUNT = None\n",
+ " LOGIN_PASSWORD = None\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD, ca_cert_data=ca_cert_data)\n",
+ " #REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, ca_cert_data=ca_cert_data)\n",
+ " # Login with the Redfish client\n",
+ " if ca_cert_data is None:\n",
+ " REDFISHOBJ.login()\n",
+ " else:\n",
+ " REDFISHOBJ.login(auth='certificate')\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ "\n",
+ " #if account_collection_uri and accounts:\n",
+ " #add specified account\n",
+ " (ilogen,_) = get_gen(REDFISHOBJ)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) !=4:\n",
+ " add_ilo_user_account(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD,ROLE_ID,PRIVILEGE_DICT)\n",
+ " else:\n",
+ " add_ilo_user_account_gen9(REDFISHOBJ,ACCOUNT_LOGIN_NAME,ACCOUNT_USER_NAME,ACCOUNT_PASSWORD)\n",
+ " \n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "acf871b9",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Bhuvan/index.ipynb b/examples/Jupyter_notebooks/HPECTY/Bhuvan/index.ipynb
new file mode 100644
index 0000000..6bb46a5
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Bhuvan/index.ipynb
@@ -0,0 +1,303 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "Scripts related to BIOS
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fa8b0fad",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change BIOS Settings | \n",
+ " Update BIOS Settings for iLO server | \n",
+ " PATCH | \n",
+ " BIOS_ChangeSettings | \n",
+ "
\n",
+ " \n",
+ " | BIOS Default | \n",
+ " Update BIOS to default setting | \n",
+ " POST | \n",
+ " BIOS_RevertToDefault | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "Scripts related to Users
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf10b943",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Add User Account | \n",
+ " Add new user account | \n",
+ " PATCH | \n",
+ " Add user account | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e16cdec",
+ "metadata": {},
+ "source": [
+ "Scripts related to Booting
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616fef86",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Change Boot Order | \n",
+ " Change iLOs boot ordert | \n",
+ " PATCH | \n",
+ " Change_Boot_Order | \n",
+ "
\n",
+ " \n",
+ " | Change Temporary Boot Order | \n",
+ " Change iLOs temporary boot ordert | \n",
+ " PATCH | \n",
+ " Change_Temp_Boot_Order | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a39acd4",
+ "metadata": {},
+ "source": [
+ "Scripts related to Firmware
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7f7d0e2",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Upload Firmware to iLO repository | \n",
+ " Script for uploading firmware to the iLO Repository for flashing | \n",
+ " | \n",
+ " Upload_Firmware_to_iLO_repo | \n",
+ "
\n",
+ " \n",
+ " | Upload Firmware with associated COMPSIG file to iLO repository | \n",
+ " Script for uploading a firmware component with a size less than\n",
+ "32 GB, and associated Component Signature (compsig) signature file to the iLO Repository | \n",
+ " | \n",
+ " Upload_Firmware_iLO_Repo_with_COMPSIG | \n",
+ "
\n",
+ " \n",
+ " | Update Firmware | \n",
+ " Script for updating Firmware via HTTP URL | \n",
+ " | \n",
+ " Update_iLO_Firmware | \n",
+ "
\n",
+ " \n",
+ " | View Firmware Inventory | \n",
+ " Script for viewing the firmware inventory on HPE iLO systems | \n",
+ " | \n",
+ " Software_Firmware_Inventory | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a224da35",
+ "metadata": {},
+ "source": [
+ "Scripts related to ESKM (Enterprise Secure Key Manager)
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b44242b9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Test ESKM Connection | \n",
+ " Script for testing connection to the ESKM system for HPE iLO systems | \n",
+ " | \n",
+ " Test_ESKM_Connection | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a0d4cfe3",
+ "metadata": {},
+ "source": [
+ "Scripts related to Power
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e8055b18",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Get Power Metrics Average | \n",
+ " Script for gathering the power metrics average on HPE iLO systems | \n",
+ " | \n",
+ " Get_Powermetrics_Average | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bcbac905",
+ "metadata": {},
+ "source": [
+ "Miscellaneous Scripts
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "610e17bf",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Example Data Resopnses | \n",
+ " Example Script for expanding data responses | \n",
+ " | \n",
+ " Expand_data | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "347cbdcf",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ahs_data.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ahs_data.ipynb
new file mode 100644
index 0000000..5ad742c
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ahs_data.ipynb
@@ -0,0 +1,253 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e2d7d850",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Clearing AHS data for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88f096f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Clearing AHS(Active Health System) data!!!\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to clear AHS data. This code is written in Python and uses the redfish library to perform the required operations
As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1525f25",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e15955c9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9615aea",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our clear_ahs_data to function overview, in the end this will clear ahs data.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
clear_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the Managers member's response object with different
odata_id we get a bios uri . Then again an http GET request is made and response is stored in
active_health_system_response.\n",
+ " Then we set the
active_health_system_clear_log_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else if the resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set
active_health_system_uri and
get active_health_system_response settings of the user through redfish object and then then set the path to post the action of clearing ahs data that we will perform.\n",
+ "
\n",
+ "\n",
+ "5. We will post the
active_health_system_clear_log_uri and the body to the Redfish Client through Redfish Object\n",
+ "\n",
+ " Ultimately if the operation was successful without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16042277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ahs_data(_redfishobj):\n",
+ "\n",
+ " active_health_system_clear_log_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response.obj['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " break\n",
+ "\n",
+ " if active_health_system_clear_log_uri:\n",
+ " body = {\"Action\": \"HpeiLOActiveHealthSystem.ClearLog\"}\n",
+ " resp = _redfishobj.redfish_client.post(active_health_system_clear_log_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e7543eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "
\n",
+ " \n",
+ "2. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call clear_ahs_data with our redfish object and rest the settings to default.
\n",
+ "
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1557bfee",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "270f99bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ahs_data(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e685a623",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb
new file mode 100644
index 0000000..2534c6b
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/clear_ilo_iel_iml_log.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "89dc5655",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Clear iLO Logs
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "898cbb84",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
for clearing out the iLO event log and management log at server side! As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98f3c2dd",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "935d8f7c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ef3013ef",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This cell gives overview about of the function used to clear event logs such as IML and IEL logs.
\n",
+ "The IML provides a record of historical events that have occurred on the server and the IEL is the iLO event log provides record of significant events detected by iLO.\n",
+ " \n",
+ "1. When the resource directory is disabled then we simply navigate through the API for obtaining the relevant uri.\n",
+ " The series of HTTP get requests aims to extracts log_services_response so as to get the path of the directory for which IEL and IML logs need to be cleared.\n",
+ "
\n",
+ "2. Else if the resource directory enabled then rather we can simply extract the uri by #LogService.attribute inside the instance['odatatype'] dictionary and again make a HTTP get request to obtain the required uri.\n",
+ "
\n",
+ "3. After obtaining the uri we just need to make changes on the same location using a post request so as to clear IEL and IML logs successfully. For this body dictionary contains the attribute to be changed and IEL/IML are searched in the path of clear_log_services_uri and the respective changes are made by redfishobj.post(path,body).\n",
+ "
\n",
+ " \n",
+ "4. Later we also check for the response returned by the server side. If the response is anything outside of status code with 200 then error message gets rendered on the webpage else the success message is printed out with the response dictionary returned by the server.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "a7abae2a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ilo_event_log(_redfishobj, clear_IML_IEL):\n",
+ "\n",
+ " clear_log_services_uri = []\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " log_services_uri = systems_members_response.obj['LogServices']['@odata.id']\n",
+ " log_services_response = _redfishobj.get(log_services_uri)\n",
+ " log_services_uris = log_services_response.obj['Members']\n",
+ " for log_services_uri in log_services_uris:\n",
+ " log_services_response = _redfishobj.get(log_services_uri['@odata.id'])\n",
+ " clear_log_services_uri.append(log_services_response.obj['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#LogService.' in instance['@odata.type']:\n",
+ " log_service_uri = instance['@odata.id']\n",
+ " clear_log_services_uri.append(_redfishobj.get(log_service_uri).dict['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ "\n",
+ " if clear_log_services_uri:\n",
+ " body = {\"Action\": \"LogService.ClearLog\"}\n",
+ " for path in clear_log_services_uri:\n",
+ " if (\"IEL\" in clear_IML_IEL and \"IEL\" in path) or (\"IML\" in clear_IML_IEL and \\\n",
+ " \"IML\" in path):\n",
+ " if \"IEL\" in path:\n",
+ " sys.stdout.write(\"Clearing IEL log.\\n\")\n",
+ " else:\n",
+ " sys.stdout.write(\"Clearing IML log.\\n\")\n",
+ " resp = _redfishobj.post(path, body)\n",
+ " else:\n",
+ " continue\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "331b8289",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. The Main function
\n",
+ "The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ " \n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "4. If server is down or Unreachable we get server not reachable message!
\n",
+ "5. Else if no error is encountered a function call is made i.e. clear_ilo_event_log(REDFISHOBJ, CLEAR_IEL_IML)that is responsible for handling clearing all the IEL and IML logs at the server side.
\n",
+ "6. Lastly, REDFISHOBJ.logout logs us out of the system and ends the session.\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f120e784",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4143942b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ " CLEAR_IML_IEL = \"IML\" # provide either the string IML or IEL\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ilo_event_log(REDFISHOBJ, CLEAR_IML_IEL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f702c0ae",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/set_syslogserver.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/set_syslogserver.ipynb
new file mode 100644
index 0000000..01453fb
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/ahs_syslog_iml/set_syslogserver.ipynb
@@ -0,0 +1,283 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b92b79fb",
+ "metadata": {},
+ "source": [
+ "Setting remote syslog server
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ed959e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Setting remote syslog server\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to set remote syslog server. This code is written in Python and uses the redfish library to perform the required operations
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a91bf91",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
ilorest_util\n",
+ "
argparse \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6eed1f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6393e74d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our set_syslog function overview
\n",
+ " This function sets the remote syslog server and enables remote syslog on an iLO system.
\n",
+ "1. It takes two parameters:\n",
+ "
\n",
+ " - _redfishobj: an object representing the connection to the iLO device through the Redfish API.
\n",
+ " - syslog_server: a string representing the IP address or hostname of the remote syslog server.
\n",
+ "2. The function first retrieves the model information of the system, which is used to determine the Oem (Original equipment manufacturer) name, as the endpoint structure and payload might differ based on the manufacturer. It determines the model of the server by sending a GET request to the
/redfish/v1/Systems/1/ URI and extracting the
Model attribute from the response.
\n",
+ "3. It checks if the model contains \"Gen9\" or \"Gen8\". If either of them is present, it sets the \"hp\" variable to \"Hp\". Otherwise, it sets it to \"Hpe\".
\n",
+ "4. It then constructs the URI for the syslog configuration resource and sends a PATCH request with the request body to set the remote syslog server and enable remote syslog.
\n",
+ " 5. Finally, it calls the
ilo_response, passing the
_redfishobj and
resp (response) as arguments. This function handles response from the server.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2971240e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_syslog(_redfishobj, syslog_server):\n",
+ "\n",
+ " model_uri = \"/redfish/v1/Systems/1/\"\n",
+ " model = _redfishobj.get(model_uri).obj['Model']\n",
+ " print (model)\n",
+ " if \"Gen9\" in model or 'Gen8' in model:\n",
+ " hp = \"Hp\"\n",
+ " else:\n",
+ " hp = \"Hpe\"\n",
+ "\n",
+ " syslog_uri = \"/redfish/v1/Managers/1/NetworkService/\"\n",
+ "\n",
+ " body = {\"Oem\": {hp: {\"RemoteSyslogServer\": syslog_server, \"RemoteSyslogEnabled\": True}}}\n",
+ " resp = _redfishobj.patch(syslog_uri, body)\n",
+ " ilo_response(_redfishobj, resp)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1fdc6d56",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is ilo_response function overview
\n",
+ " The ilo_response function is responsible for handling the response from the iLO server.
\n",
+ "1. It takes two parameters: _redfishobj (Redfish client object) and resp (response object).
\n",
+ "2. It checks the status code of the response. If it is equal to 400, it indicates a client error.
\n",
+ "3. It tries to extract and print the extended error information from the response using the key error ['@Message.ExtendedInfo'].\n",
+ "If there is an exception while accessing the extended error information, it writes an error message to the standard error stream.
\n",
+ "4. If the status code is not 400 but is not equal to 200 either, it indicates an HTTP response error.\n",
+ "It writes an error message to the standard error stream, indicating the HTTP response status.
\n",
+ "5. If the status code is 200, it indicates a successful response.\n",
+ "It prints the message \"Success\" to indicate the operation was successful.
\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b2db998f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ilo_response(_redfishobj, resp):\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d95a2d40",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
4. This is Main function overview.
\n",
+ "1. An argument parser is initialized to parse the command-line arguments passed to the script. The parser expects arguments such as iLO url, username, password, and syslog server IP.
\n",
+ "2.The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "3. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "5. The get_gen function is called to retrieve the iLO generation number of the server.\n",
+ " Depending on the iLO generation number, the set_syslog function is called with the Redfish client object and the syslog server IP address.
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "750b6ae8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3681c0d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-s',\n",
+ " '--syslog_server',\n",
+ " dest='syslog_server',\n",
+ " action=\"store\",\n",
+ " required=True,\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " set_syslog(redfish_obj, options.syslog_server)\n",
+ " else:\n",
+ " set_syslog(redfish_obj, options.syslog_server)\n",
+ " redfish_obj.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f91c6419",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_iscsi.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_iscsi.ipynb
new file mode 100644
index 0000000..84621c5
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_iscsi.ipynb
@@ -0,0 +1,252 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a036d81b",
+ "metadata": {},
+ "source": [
+ "Setting an ISCSI boot instance for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0ffb0a82",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library Here is an example to
set an ISCSI boot instance for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " Also do run each succesive cell of code \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc60fabf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6b0ad498",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d2c00edc",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. Below is a set_bios_iscsi that sets the ISCSI boot instance for HPE iLO systems.
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. The function takes two parameters:
_redfishobj (a Redfish client object) and
iscsi_properties (a dictionary containing the iSCSI properties to be set).
\n",
+ "2. It calls the
get_resource_directory function to obtain the resource directory from the Redfish service. If
DISABLE_RESOURCE_DIR is set to True or the resource directory is empty, the code retrieves the necessary URIs manually.
\n",
+ "3.
If the resource directory is disabled or not available, the code fetches the systems URI and retrieves the
BIOS URI from the response. The code retrieves the
iSCSI URI from the BIOS response and fetches the
iSCSI data.
\n",
+ "4.
If the resource directory is enabled and available, the code iterates over the instances in the resource directory and searches for the iSCSI instance based on its type.
\n",
+ "5.
If the iSCSI data is found, the code loops over the iSCSI sources and checks if the iSCSIBootInstance property matches the current index. If a match is found, the code updates the iSCSI properties for that instance.
\n",
+ "6. The code sends a
PATCH request to the iSCSI URI with the updated iSCSI sources data.
\n",
+ "7. If the response status is 400, indicating an error, the code attempts to print the error message. If the response status is not 200 or 201, an error message is printed.
\n",
+ "8. If the response status is 200, the code indicates success and suggests that a system reboot will be required to apply the changes. It also prints the response details.
\n",
+ "\n",
+ "The loop is broken after processing the desired iSCSI instance.\n",
+ "
\n",
+ " \n",
+ "
\n",
+ " \n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f6bfe14a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_bios_iscsi(_redfishobj, iscsi_properties):\n",
+ "\n",
+ " iscsi_uri = None\n",
+ " iscsi_data = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " iscsi_uri = bios_response.obj.Oem.Hpe.Links['iScsi']['@odata.id']\n",
+ " iscsi_data = _redfishobj.get(iscsi_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiSCSISoftwareInitiator.' in instance['@odata.type']:\n",
+ " iscsi_uri = instance['@odata.id']\n",
+ " iscsi_data = _redfishobj.get(iscsi_uri)\n",
+ "\n",
+ " if iscsi_data:\n",
+ " for indx, inst in enumerate(iscsi_data.obj['iSCSISources']):\n",
+ " if iscsi_properties['iSCSIBootInstance'] == indx:\n",
+ " iscsi_data.dict['iSCSISources'][indx].update(iscsi_properties)\n",
+ " resp = _redfishobj.patch(iscsi_uri, {'iSCSISources' : iscsi_data.dict['iSCSISources']})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the\n",
+ " #iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], \\\n",
+ " indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " print(json.dumps(resp.ori, indent=4, sort_keys=True))\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \" \\\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! A system reboot will be required to complete the change.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "55289e4d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - We are passing the required information to change the password of iLO user account i.e. base_url, username, password
\n",
+ " - If server is down or Unreachable we get server not reachable message.
\n",
+ " - The set_bios_iscsi function is called, passing the RedfishClient object (REDFISHOBJ) and the iSCSI properties dictionary (ISCSI_PROPERTIES).
\n",
+ "\n",
+ "- After setting the iSCSI properties, the logout method of the RedfishClient object is called to end the session with the server.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9b5acb64",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11b07dec",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #iscsi properties\n",
+ " ISCSI_PROPERTIES = {\"iSCSIBootInstance\": 2, \\\n",
+ " \"iSCSITargetName\": \"Target\", \\\n",
+ " \"iSCSIAttemptName\": \"Empty\", \\\n",
+ " \"iSCSIConnectRetry\": 5}\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_bios_iscsi(REDFISHOBJ, ISCSI_PROPERTIES)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1c7d1d0b",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_password.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_password.ipynb
new file mode 100644
index 0000000..bcfc647
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/bios/set_bios_password.ipynb
@@ -0,0 +1,248 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "d357d38b",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Setting Bios Password
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fce7e904",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library Here is an example to
change bios password for HPE iLO system!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " Also do run each succesive cell of code \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a89aa82f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8cf61dff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "828be423",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. Below is the set_bios_password function, through which we can change the password of bios system.
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
set_bios_setting function we are taking three parameters i.e.
Redfish object,
new_password and exisiting password as
bios_password. Also
resource_instances variable is being obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
If the resource directory was disabled we are making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings and later make changes to the existing password.
- For that purpose simply we are making series of get requests.
\n",
+ " - After navigating through iLO rest api we actually save the http address of location where bios settings are present inside bios_uri
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3.
Else if the resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "4.
If bios_uri is not null after making above operations, we can perform the required actions to change the bios password.
\n",
+ " - Following up we make get request and obtain the URL of the location where we are actually going to make the changes.
- Ultimately, we make a post request by passing the bios_change_pass_uri and body dictionary that contains the changes made to the password.
\n",
+ " - The job of post request here is to update the password at the provided location and send a response whether the job was done properly or not.
\n",
+ " \n",
+ " If the reponse status code was anything other than 200 or 201 then we can print out the response status code and error message.
\n",
+ " Else we print out success message with the response obtained after making post request.\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "ee515d74",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_bios_password(_redfishobj, new_password, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_uri:\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_change_pass_uri = bios_data.obj['Actions']['#Bios.ChangePassword']['target']\n",
+ " body = dict()\n",
+ " body[\"PasswordName\"] = \"Administrator\"\n",
+ " body[\"OldPassword\"] = bios_password\n",
+ " body[\"NewPassword\"] = new_password\n",
+ " resp = _redfishobj.post(bios_change_pass_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b93c0d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - We are passing the required information to change the password of iLO user account i.e. base_url, username, password
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Once everything is done you are automatically logged out.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "34f69788",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38b9fd3a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD =getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #new BIOS password\n",
+ " NEW_BIOS_PASSWORD = \"password\"\n",
+ " #old BIOS password\n",
+ " OLD_BIOS_PASSWORD = \"password\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_bios_password(REDFISHOBJ, NEW_BIOS_PASSWORD, OLD_BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71f23513",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/ilo_license/set_license_key.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/ilo_license/set_license_key.ipynb
new file mode 100644
index 0000000..45f4a8f
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/ilo_license/set_license_key.ipynb
@@ -0,0 +1,262 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7d91ced6",
+ "metadata": {},
+ "source": [
+ "Setting license key
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "11b0fe9d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting license key. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6cbd5f7c",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f0fa1574",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7daccb24",
+ "metadata": {},
+ "source": [
+ "2. This is our set_license_key function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
set_license_key function we are taking two parameters i.e.
_redfishobj and
ilo_key. In the
set_license_key function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about license key is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the license service about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The license service information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeiLOLicense type is present in
@odata.type attribute then we will store information about license key in ilo_lic_uri and break out of iteration.\n",
+ "
\n",
+ "5.
If ilo_lic_uri is not null after making above operations, we can perform the required actions to set license key. \n",
+ "
\n",
+ " - The function sends a GET request to the iLO license service to retrieve the current license data. If the ConfirmationRequest field exists, it is printed to the console; otherwise, the LicenseKey field is printed.
\n",
+ "- The function sends a POST request to the iLO license service with the new license key provided in the ilo_key argument.
\n",
+ " - The job of post request here is to set the license key at the provided location and send a response whether the job was done properly or not.
\n",
+ " - If the response status is 400, the function attempts to print the extended error message provided by iLO. If the status is not 200 or 201, the function prints an error message to the console.
\n",
+ "- If the response status is 200, the function prints a success message to the console along with the response JSON.
\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bacca62e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_license_key(_redfishobj, ilo_key):\n",
+ "\n",
+ " ilo_lic_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " ilo_lic_uri = managers_members_response.obj.Oem.Hpe.Links['LicenseService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOLicense.' in instance['@odata.type']:\n",
+ " ilo_lic_uri = instance['@odata.id']\n",
+ "\n",
+ " if ilo_lic_uri:\n",
+ " ilo_license_collection = _redfishobj.get(ilo_lic_uri)\n",
+ " ilo_license_member_uri = next(iter(ilo_license_collection.obj['Members']))['@odata.id']\n",
+ " try:\n",
+ " ilo_license_data = _redfishobj.get(ilo_license_member_uri).obj['ConfirmationRequest']\\\n",
+ " ['EON']\n",
+ " except KeyError:\n",
+ " sys.stdout.write(\"This machine will not show the full License Key.\\n\")\n",
+ " ilo_license_data = _redfishobj.get(ilo_license_member_uri).obj['LicenseKey']\n",
+ "\n",
+ " sys.stdout.write(\"Current iLO License Data:\\n\")\n",
+ " print(json.dumps(ilo_license_data, indent=4, sort_keys=True))\n",
+ " resp = _redfishobj.post(ilo_lic_uri, {'LicenseKey' : ilo_key})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stderr.write(\"Check the validity of your license key...\\n\")\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \" \\\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "abfa5bd8",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to set_license_key function to set license key of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7d4c55f5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38798e69",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # Must be a valid iLO License Key\n",
+ " ILO_LICENSE_KEY = \"XXXX-XXXX-XXXX-XXXX-XXXXX\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_license_key(REDFISHOBJ, ILO_LICENSE_KEY)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3be89a3",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/index.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/index.ipynb
new file mode 100644
index 0000000..bff8826
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/index.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "Scripts related to ahs_syslog_iml
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fa8b0fad",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Clear AHS data | \n",
+ " Clear active health state data of iLO server | \n",
+ " DELETE | \n",
+ " clear_ahs_data | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set remote syslog server\t | \n",
+ " Setting Remote syslog Server for an HPE iLO management processor. | \n",
+ " PATCH | \n",
+ " set_syslogserver | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Clear iLO IEL IML log\t | \n",
+ " Clearing out the iLO event log and management log at server side | \n",
+ " DELETE | \n",
+ " clear_ilo_iel_iml_log | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "Scripts related to server_manager
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf10b943",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Computer Details | \n",
+ " Get all the available computer/hosts details in iLO\t | \n",
+ " GET | \n",
+ " computer_details | \n",
+ "
\n",
+ " \n",
+ " | Set Server Asset Tag | \n",
+ " Setting server asset tag\t | \n",
+ " PATCH | \n",
+ " set_server_asset_tag | \n",
+ "
\n",
+ " \n",
+ " | Set UID Light | \n",
+ " Setting UID Light | \n",
+ " PATCH | \n",
+ " set_uid_light | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "01ee71dd",
+ "metadata": {},
+ "source": [
+ "Scripts related to BIOS
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fbce5754",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set bios password | \n",
+ " Change bios password for HPE iLO system | \n",
+ " PATCH | \n",
+ " set_bios_password | \n",
+ "
\n",
+ " \n",
+ " | Set bios ISCSI | \n",
+ " Setting an ISCSI boot instance for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_bios_iscsi | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0140b004",
+ "metadata": {},
+ "source": [
+ "Scripts related to SNMP
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d60f6ff8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Configure SNMP | \n",
+ " Configuring SNMP for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp | \n",
+ "
\n",
+ " \n",
+ " | Configure SNMP trap source | \n",
+ " Configuring SNMP trap source for HPE iLO systems | \n",
+ " PATCH | \n",
+ " configure_snmp_trap_source | \n",
+ "
\n",
+ " \n",
+ " | Set SNMP alert destination | \n",
+ " Setting SNMP alert destination for HPE iLO systems | \n",
+ " PATCH | \n",
+ " set_snmp_alert | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aff5c9ed",
+ "metadata": {},
+ "source": [
+ "Scripts related to ilo_license
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9cfb10a",
+ "metadata": {},
+ "source": [
+ "\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Set License Key\t | \n",
+ " Setting License Key | \n",
+ " PATCH | \n",
+ " set_license_key | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/computer_details.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/computer_details.ipynb
new file mode 100644
index 0000000..ee8373c
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/computer_details.ipynb
@@ -0,0 +1,230 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "Gathering the computer system details
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library Here is an example to
get_computer_details!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. We are importing all the necessary modules from the ilorest library!
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is the function to get the computer details requested.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
computer_details function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about computer is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the computer data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if computerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally print the Computer Details through
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def computer_details(_redfishobj):\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " print(\"\\n\\nPrinting computer system details:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " Enter iLO url, Username, Password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, but if Server is not avaialbe we get an error saying \"server unreachable\".
\n",
+ "
\n",
+ "5. Then we call computer_details with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the iLO.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " computer_details(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_server_asset_tag.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_server_asset_tag.ipynb
new file mode 100644
index 0000000..f919e9d
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_server_asset_tag.ipynb
@@ -0,0 +1,248 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "c3169c50",
+ "metadata": {},
+ "source": [
+ "Setting server asset tag
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "70635f68",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting server asset tag. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f176e2a7",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cbe979de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "616c5812",
+ "metadata": {},
+ "source": [
+ "2. This is our set_server_asset_tag function overview.
\n",
+ "
\n",
+ "1. The
set_server_asset_tag function sets the server asset tag on an iLO device. The function takes two parameters: _redfishobj and tag. \n",
+ "
\n",
+ " - _redfishobj is a Redfish client object that represents the connection to the server
\n",
+ " - tag is a string that represents the asset tag to be set for the server.
\n",
+ "
\n",
+ "2. In the
set_server_asset_tag function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.
\n",
+ "3. In the ILO rest api the information about server asset tag is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the server asset tag of iLO system.
\n",
+ "4. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "5. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #ComputerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.
\n",
+ "6.The function then calls the
patch() method to update the system's AssetTag property with the new tag provided as input to the function.
\n",
+ "7. If the iLO device responds with a status code outside of 200 or 201, the function attempts to access the iLO extended message info to see what went wrong.
\n",
+ "8. If the patch() operation is successful, the updated asset tag is printed to the console. The function then waits for 10 seconds before retrieving and displaying the updated asset tag.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f4e166b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_server_asset_tag(_redfishobj, tag):\n",
+ "\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response and systems_members_uri and tag:\n",
+ " print(\"Current Asset Tag: \\'%s\\'\\n\" % systems_members_response.dict.get(\"AssetTag\"))\n",
+ "\n",
+ " resp = _redfishobj.patch(systems_members_uri, {\"AssetTag\" : tag})\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " time.sleep(10) #going to wait 10 seconds before obtaining the LED indicator state\n",
+ " sys.stdout.write(\"\\nUpdated Asset Tag: \\'%s\\'\\n\" % _redfishobj.\\\n",
+ " get(systems_members_uri).dict.get(\"AssetTag\"))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ef4f1fb5",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to set_server_asset_tag to set server asset tag of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bf946980",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "606190a9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #asset tag property in computer systems\n",
+ " ASSET_TAG = \"Asset01\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_server_asset_tag(REDFISHOBJ, ASSET_TAG)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63db964c",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_uid_light.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_uid_light.ipynb
new file mode 100644
index 0000000..72aa3b0
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/server_manager/set_uid_light.ipynb
@@ -0,0 +1,275 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "8ce5d6a0",
+ "metadata": {},
+ "source": [
+ "Setting the UID light
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b76e816",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Setting UID light\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to set uid light. This code is written in Python and uses the redfish library to perform the required operations
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0581e350",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "62892493",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "SyntaxError",
+ "evalue": "invalid syntax (Temp/ipykernel_9848/2405422628.py, line 1)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;36m File \u001b[1;32m\"C:\\Users\\Win10\\AppData\\Local\\Temp/ipykernel_9848/2405422628.py\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m \u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
+ ]
+ }
+ ],
+ "source": [
+ "
\n",
+ "Welcome to
python-iLOrest-library Here is an example to
Setting UID light\n",
+ " This Jupyter Notebook will contains a example code to demonstrate how to set uid light. This code is written in Python and uses the redfish library to perform the required operations
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " Please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1eb087ac",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2. This is our set_uid_light to function overview, in the end this will set uid light.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "1. This is a function that uses the Redfish API to toggle the UID (Universal Identification) LED on a computer system.\n",
+ " The function takes a Redfish connection object
_redfishobj as its only argument.
\n",
+ "2. In the
set_uid_light function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ "3. In the iLO rest api the information about UID light is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the UID light settings of iLO system.\n",
+ "
\n",
+ "4. In the system members response object with different
odata_id we get a system uri . Then again an http GET request is made and response is stored in
system_response. Then we set the
system_members_uri.
\n",
+ "5. Else if resource directory is enabled then we will simply iterate through all instances inside resources and if #ComputerSystem attribute is present in @odata.type attribute then we'll set system_members_uri and get system_members_response settings of the user through redfish object.
\n",
+ "6.It sets the body[\"IndicatorLED\"] key to Lit if the current value of the IndicatorLED property is Off, or to \"Off\" otherwise.
\n",
+ "7. It sends an HTTP PATCH request to the obtained URI with the body payload to update the IndicatorLED property.
\n",
+ "8. If the response status code is not 200 (OK) or 201 (Created), it prints an error message and exits.
\n",
+ "9. If the response status code is 200 or 201, it waits for 10 seconds to allow the firmware to update the LED status, and then sends a GET request to the same URI to obtain the updated resource representation of the computer system.
\n",
+ "10. It prints the updated value of the IndicatorLED property.
\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "07276165",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_uid_light(_redfishobj):\n",
+ "\n",
+ " body = dict()\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " if systems_members_response and systems_members_uri:\n",
+ " print(\"Current Indicator LED Status: \\'%s\\'\\n\" % systems_members_response.dict.\\\n",
+ " get(\"IndicatorLED\"))\n",
+ " if \"Off\" in systems_members_response.dict.get(\"IndicatorLED\"):\n",
+ " print(\"Will illuminate indicator LED.\\n\")\n",
+ " body[\"IndicatorLED\"] = \"Lit\"\n",
+ " else:\n",
+ " print(\"Will extinguish indicator LED.\\n\")\n",
+ " body[\"IndicatorLED\"] = \"Off\"\n",
+ "\n",
+ " resp = _redfishobj.patch(systems_members_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " time.sleep(10) #going to wait 10 seconds before obtaining the LED indicator state\n",
+ " sys.stdout.write(\"\\nUpdated Indicator LED Status: \\'%s\\'\\n\" % _redfishobj.\\\n",
+ " get(systems_members_uri).dict['IndicatorLED'])\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "70d73b57",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3. This is Main function overview.
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by Redfish object which is created by Redfish Client
\n",
+ "
\n",
+ " \n",
+ "2. Redfish Client class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish object is created with the help of Redfish Client class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call set_uid_light with our redfish object to set UID light.
\n",
+ "
\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3e4a9804",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ea7ed17c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address, account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_uid_light(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "377dc76a",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp.ipynb
new file mode 100644
index 0000000..69cefa1
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp.ipynb
@@ -0,0 +1,257 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "979defcc",
+ "metadata": {},
+ "source": [
+ "
Configuring SNMP for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " Welcome to
python-iLOrest-library This is an example of
configuring SNMP for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ccd0447f",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'redfish'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_4196/1287542820.py\u001b[0m in \u001b[0;36m
\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mjson\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mRedfishClient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'redfish'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory \n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "2. This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alerts):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related information of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d5fe2f86",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address, account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " ALERTS_ENABLED = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_ENABLED, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp_trap_source.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp_trap_source.ipynb
new file mode 100644
index 0000000..2b3ce58
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/configure_snmp_trap_source.ipynb
@@ -0,0 +1,238 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0a6c95aa",
+ "metadata": {},
+ "source": [
+ "Configuring SNMP trap source for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "594a0e06",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Welcome to
python-iLOrest-library This is an example of
configuring SNMP trap source for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25be0e98",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f16a98ad",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'redfish'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_25528/1522814575.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mjson\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mRedfishClient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'redfish'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c2b4d45",
+ "metadata": {},
+ "source": [
+ "2. This is our configure_snmp function overview, in the end this will give us with snmp service related information.
\n",
+ " \n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the snmp service information.\n",
+ "\n",
+ " \n",
+ "\n",
+ " \n",
+ "1. In the ILO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "2. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if power snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b53e8e73",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ " def configure_snmp(_redfishobj):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " # print(managers_members_response.obj['Oem']['Hpe']['Links'])\n",
+ " # exit(0)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['SNMPService']['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " # resp = _redfishobj.get(snmp_service_uri)\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " # exit(0)\n",
+ " # TrapSourceHostname : Manager or System\n",
+ " body = {\"TrapSourceHostname\": \"System\"}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b852d783",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related info of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80f7da07",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "610979dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " if len(sys.argv) <= 3:\n",
+ " sys.stderr.write(\"ERROR: We need 3 arguments. \\nUsage: change-snmp.py \"\n",
+ " \"ILOIPADDR ILOUSER ILOPASSWORD \\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " SYSTEM_URL = \"https://\" + sys.argv[1]\n",
+ " LOGIN_ACCOUNT = sys.argv[2]\n",
+ " LOGIN_PASSWORD = sys.argv[3]\n",
+ "\n",
+ " try:\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,\n",
+ " password=LOGIN_PASSWORD)\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b5c8a5",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/set_snmp_alert.ipynb b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/set_snmp_alert.ipynb
new file mode 100644
index 0000000..cea51c3
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Dharitri/snmp/set_snmp_alert.ipynb
@@ -0,0 +1,315 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "80ca2bf5",
+ "metadata": {},
+ "source": [
+ "Setting SNMP alert destination
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "647c7374",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library This is an example of
setting SNMP alert destination. As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ce2b4b70",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e6a53c06",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfd0ef73",
+ "metadata": {},
+ "source": [
+ "2. This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "269747d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alertdestinations, DISABLE_RESOURCE_DIR):\n",
+ " snmp_service_uri = None\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " #body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " body = {\"AlertDestinations\": snmp_alertdestinations}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ca33ee48",
+ "metadata": {},
+ "source": [
+ "3. This is our set_snmp_alert_destination function overview.
\n",
+ "
\n",
+ "1. The
set_snmp_alert_destination function sets the SNMP alert destinations on an iLO device. The function takes three parameters: _redfishobj, snmp_service_uri, and alert_destination_list. \n",
+ "
\n",
+ " - _redfishobj is the Redfish client object.
\n",
+ " - snmp_service_uri is the URI for the SNMP service on the iLO device.
\n",
+ " - alert_destination_list is a list of dictionaries containing the SNMP alert destinations to set.
\n",
+ "
\n",
+ "2. The function gets the current SNMP service data using
_redfishobj.get() and checks if the
AlertDestinations property is available/modifyable.
\n",
+ "3. If the property is available/modifyable, the function sends a PATCH request with the updated alert destinations using
_redfishobj.patch().
\n",
+ "4. If the iLO device responds with a status code outside of 200 or 201, the function attempts to access the iLO extended message info to see what went wrong.
\n",
+ "5. If the patch operation is successful, the function prints the response and gets the updated SNMP alert destination data using
_redfishobj.get().
\n",
+ "6. The updated SNMP alert destination data is printed to the console using
json.dumps() and
print().
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c91c0fb8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_snmp_alert_destination(_redfishobj, snmp_service_uri, alert_destination_list):\n",
+ " data = _redfishobj.get(snmp_service_uri)\n",
+ " if data.dict.get(\"AlertDestinations\"):\n",
+ " resp = _redfishobj.patch(snmp_service_uri, {'AlertDestinations': alert_destination_list})\n",
+ " else:\n",
+ " raise Exception(\"\\'AlertDestinations\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nPatch operation successful!\\n\\nResponse:\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " snmp_service_response = _redfishobj.get(snmp_service_uri).dict.get('AlertDestinations')\n",
+ " print(\"\\n\\nPrinting updated SNMP alert destination:\\n\")\n",
+ " print(json.dumps(snmp_service_response, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9fdd0d40",
+ "metadata": {},
+ "source": [
+ "4. This is Main function overview.
\n",
+ "
The Main function \n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - It checks the generation of iLO by calling the get_gen function and prints the iLO generation.\n",
+ "
- If the iLO generation is 5, it calls the configure_snmp function to configure the SNMP service with the read communities and alerts destination, and disable resource directory flag.
\n",
+ "- If the iLO generation is not 5, it calls the set_snmp_alert_destination function to set the SNMP alert destination with the alert destination list for iLO4.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a2f6ba5",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27378983",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " #SYSTEM_URL = \"https://15.146.46.45\"\n",
+ " #LOGIN_ACCOUNT = \"admin\"\n",
+ " #LOGIN_PASSWORD = \"admin123\"\n",
+ "\n",
+ " SYSTEM_URL = sys.argv[1]\n",
+ " LOGIN_ACCOUNT = sys.argv[2]\n",
+ " LOGIN_PASSWORD = sys.argv[3]\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " #ALERTS_ENABLED = True\n",
+ " #Alert Destination\n",
+ " ALERTS_DESTINATION = [\"1.1.1.1\",\"2.2.2.2\"]\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ " snmp_service_uri = \"/redfish/v1/Managers/1/SNMPService/\"\n",
+ "\n",
+ " # Number of max alert destination supported on iLO4 and iLO5 is different\n",
+ " alert_destination_list = [\"ILOCN771702NJ\", \"15.146.46.55\" , \"15.146.46.58\"]\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " (ilogen,_) = get_gen(REDFISHOBJ)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_DESTINATION, DISABLE_RESOURCE_DIR)\n",
+ " else:\n",
+ " set_snmp_alert_destination(REDFISHOBJ, snmp_service_uri, alert_destination_list)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28ec396f",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ahs_data.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ahs_data.ipynb
new file mode 100644
index 0000000..7427901
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ahs_data.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a597eefb",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Gathering AHS data for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28da61c7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_ahs_data!!! As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy, we'll be needing it in a while!\n",
+ "
\n",
+ "
Follow the guide below to execute without any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6c29a405",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29082d3a",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
This is our ahs gathering data function overview, in the end we will get the Active Health System data.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
get_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about the Active Health System is stored inside the
managers json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the ahs data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object with different
odata_id we get the managers members uri .\n",
+ " Then again an http GET request is made and response is stored in
managers_response_response.\n",
+ " Then we set the
active_health_system_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeiLOActiveHealthSystem attribute is present in
@odata.type attribute then we'll set active_health_system_uri and
get active_health_system_log_resp through redfish object.\n",
+ "
\n",
+ "\n",
+ "5. If this is successful, then we will open a
logfile and write
active_health_system_log_resp.ori which is the get_ahs_data to that logfile.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ahs_data(_redfishobj, logfile=\"data.ahs\"):\n",
+ "\n",
+ " active_health_system_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ "\n",
+ " if active_health_system_uri:\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_log_uri = active_health_system_response.obj.Links['AHSLocation']\\\n",
+ " ['extref']\n",
+ " active_health_system_log_resp = _redfishobj.get(active_health_system_log_uri)\n",
+ " if active_health_system_log_resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(active_health_system_log_resp.obj['error']\\\n",
+ " ['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif active_health_system_log_resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % active_health_system_log_resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " with open(logfile, 'wb') as ahsoutput:\n",
+ " ahsoutput.write(active_health_system_log_resp.ori)\n",
+ " ahsoutput.close()\n",
+ " sys.stdout.write(\"AHS Data saved successfully as: \\'%s\\'\" % logfile)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "155fb958",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter ilo url,username,password, and the path of log file
\n",
+ " \n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_ahs_data with our redfish object and logfile.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # logfile path and filename\n",
+ " LOGFILE = input(\"Enter log file path and file name: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ahs_data(REDFISHOBJ, LOGFILE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb9dca1",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a528a3",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_base_registry.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_base_registry.ipynb
new file mode 100644
index 0000000..2f93530
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_base_registry.ipynb
@@ -0,0 +1,175 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b6a26458",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User!
\n",
+ "Welcome to
python-iLOrest-library \n",
+ "This script can be used to retrieve the
base registry information from an HPE iLO (Integrated Lights Out) server.
\n",
+ "To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ "And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1dc8cc16",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ " First, we need to \"import\" certain files that provide us the functionality to get the base registry.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1087550c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the get_base_registry function. The get_base_registry function serves the purpose of retrieving the base registry information from an HPE iLO server using the HPE iLO REST API.
\n",
+ " It performs the following steps to accomplish this:
\n",
+ "1. The get_base_registry function sends a GET request to the /rest/v1/Registries endpoint of the HPE iLO server to retrieve the registry data.\n",
+ "
\n",
+ "2. It iterates through the response entries, checking for the \"Id\" field or extracting the schema name.\n",
+ "
\n",
+ "3. For each entry, it makes additional GET requests to the specified URIs to retrieve the registry information.\n",
+ "
\n",
+ "4. If successful, it displays a message and stores the registry messages in a dictionary. The function returns the dictionary containing the registry messages.\n",
+ "
\n",
+ "In summary, the get_base_registry function retrieves the base registry information by making requests to specific URIs, extracting relevant data, and storing it for further analysis and management.\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_base_registry(restobj):\n",
+ " response = restobj.get(\"/rest/v1/Registries\")\n",
+ " messages = {}\n",
+ "\n",
+ " identifier = None\n",
+ "\n",
+ " for entry in response.dict[\"Items\"]:\n",
+ " if \"Id\" in entry:\n",
+ " identifier = entry[\"Id\"]\n",
+ " else:\n",
+ " identifier = entry[\"Schema\"].split(\".\")[0]\n",
+ "\n",
+ " if identifier not in [\"Base\", \"iLO\"]:\n",
+ " continue\n",
+ "\n",
+ " for location in entry[\"Location\"]:\n",
+ " reg_resp = restobj.get(location[\"Uri\"][\"extref\"])\n",
+ "\n",
+ " if reg_resp.status == 200:\n",
+ " sys.stdout.write(\"\\tFound \" + identifier + \" at \" + \\\n",
+ " location[\"Uri\"][\"extref\"] + \"\\n\")\n",
+ " messages[identifier] = reg_resp.dict[\"Messages\"]\n",
+ " else:\n",
+ " sys.stdout.write(\"\\t\" + identifier + \" not found at \"\\\n",
+ " + location[\"Uri\"][\"extref\"] + \"\\n\")\n",
+ "\n",
+ " return messages"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "167d47fe",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "The following code establishes a connection to an HPE iLO server using the HPE iLO REST API. It sets up the necessary parameters for either local or remote server connection, creates a REST client object, logs into the iLO server, executes an example function to retrieve registry information, and logs out from the server. This code showcases how to interact with the iLO server programmatically, demonstrating the usage of the HPE iLO REST API for server management tasks.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 2: Find and return registry \" + \"\\n\")\n",
+ " get_base_registry(REST_OBJ)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_bios_settings.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_bios_settings.ipynb
new file mode 100644
index 0000000..6102d64
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_bios_settings.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# GETTING BIOS SETTINGS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
getting bios(basic input/output system) settings about HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ " In the beginning, we are having some import statements that are actually providing us with the required modules and libraries\n",
+ "for proper execution of our code.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of retrieving bios settings from iLO servers.\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the get_bios_settings function, after everything is done this function will give details about bios settings of system.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
get_bios_setting function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In case the resource directory was disabled we are using systems making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings.
- For that purpose simply we are making series of get requests.
\n",
+ " We make a final get operation by at the location bios_uri and save the response inside bios_data.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately, if bios_data variable is not null we print out information about bios settings. \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_bios_setting(_redfishobj):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing bios attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to get_bios_settings function to obtain information about bios settings of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Enter iLO IP address: 10.0.2.15\n",
+ "Enter Username: Administrator\n",
+ "Enter password: 12iso*help\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 13\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 12\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 13\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 14\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 15\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[2], line 17\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 16\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 17\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 18\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 19\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_bios_setting(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_ip.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_ip.ipynb
new file mode 100644
index 0000000..c765281
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_ip.ipynb
@@ -0,0 +1,158 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "27676c26",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Hello User!
\n",
+ "Welcome to python-iLOrest-library
\n",
+ "This script demonstrates how to retrieve the IP address of an HPE iLO (Integrated Lights-Out) server locally.
It uses the HPE iLO REST API to interact with the server and obtain the IP address information. The script establishes a connection to the iLO server, retrieves the resource directory, identifies the manager path, and retrieves the Ethernet NIC information. It then extracts the IPv4 address from the NIC information and displays it. Overall, this code focuses on obtaining the iLO IP address using the HPE iLO REST API for local server management purposes.\n",
+ "
\n",
+ "Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ad60173",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ " First, we need to \"import\" certain files that provide us the functionality to retrieve the IP address of our HPE iLO server.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bf3194e3",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the get_ilo_ip function. \n",
+ "The get_ilo_ip function retrieves the IP address of an HPE iLO (Integrated Lights-Out) server.
Here's a breakdown of its functionality:
\n",
+ "\n",
+ "The function starts by obtaining the resource directory from the provided restobj, which represents the REST object.
\n",
+ "It then iterates over the resource instances in the directory to find the manager path that corresponds to the iLO server.
\n",
+ "Once the manager path is obtained, a GET request is made to retrieve the manager information.\n",
+ "The function then retrieves the Ethernet NIC information by following the link provided in the manager response.
\n",
+ "It iterates over the Ethernet NIC items and checks if the IPv4 address is not \"0.0.0.0\". If a valid IPv4 address is found, it is written to the standard output.
\n",
+ "In summary, the get_ilo_ip function utilizes the HPE iLO REST API to locate and retrieve the IP address of an iLO server. It provides a convenient way to programmatically obtain the server's network information.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ilo_ip(restobj):\n",
+ " resource_instances = get_resource_directory(restobj)\n",
+ " if resource_instances:\n",
+ " #Get URI from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if \"Manager.\" in instance.Type:\n",
+ " manager_path = instance.href\n",
+ " break\n",
+ "\n",
+ " response = restobj.get(manager_path)\n",
+ " ethernet_rsp = restobj.get(response.dict[\"links\"][\"EthernetNICs\"][\"href\"])\n",
+ " for item in ethernet_rsp.dict[\"Items\"]:\n",
+ " if not item[\"IPv4Addresses\"][0][\"Address\"] == \"0.0.0.0\":\n",
+ " sys.stdout.write(\"\\t\" + item[\"IPv4Addresses\"][0][\"Address\"] + \"\\n\")\n",
+ " sys.stdout.write(\"%s\" % response)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c3318f0a",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "The following code establishes a connection to an HPE iLO server using the HPE iLO REST API. It sets up the necessary parameters for either local or remote server connection, creates a REST client object, logs into the iLO server, executes an example function to retrieve registry information, and logs out from the server.
\n",
+ "This code demonstrates a simple implementation to retrieve the IP address of an HPE iLO server locally. It initializes the necessary variables, creates a REST client object, logs in to the server, retrieves and prints the IP address, and finally logs out. This example showcases the usage of the HPE iLO REST API for basic server interaction."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " SYSTEM_URL = None\n",
+ " LOGIN_ACCOUNT = None\n",
+ " LOGIN_PASSWORD = None\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 52: Get iLO IP locally\\n\")\n",
+ " get_ilo_ip(REST_OBJ)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_nic.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_nic.ipynb
new file mode 100644
index 0000000..d177abd
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/get_ilo_nic.ipynb
@@ -0,0 +1,164 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "41a1448b",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User!
\n",
+ "Welcome to
python-iLOrest-library \n",
+ "This script provides an example implementation that allows you to
retrieve the network interface card (NIC) configuration of your HPE iLO server.
\n",
+ "To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ "And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25c830bd",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ " First, we are importing certain files that provide us the functionality to get the nic configuration of the server.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import LegacyRestClient\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "64642b12",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ " Below is the get_ilo_nic function. The get_ilo_nic function is responsible for retrieving the network interface card (NIC) configuration of an HPE iLO server. It takes a REST object and a parameter indicating whether to retrieve active or inactive NICs as input. Here's a brief overview of the function's steps:
\n",
+ "
The function first obtains the resource directory of the iLO server using the provided REST object. This directory contains information about the server's available resources, including the NICs.
\n",
+ "
It then searches for the NIC-related information within the resource directory by iterating through the instances and identifying the ones related to the server's manager.\n",
+ "Using the obtained NIC information, the function retrieves the NIC configuration data from the server.
\n",
+ "
Depending on the value of the get_active parameter, the function filters the retrieved NICs to either active or inactive ones.
\n",
+ "
Finally, the function outputs the relevant NIC information, including the NIC's self URL and its JSON representation.
\n",
+ "
In summary, the get_ilo_nic function allows you to fetch and categorize the NIC configuration of an HPE iLO server based on its active or inactive status. This information can be useful for monitoring and managing your server's network settings.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ilo_nic(restobj, get_active):\n",
+ " resource_instances = get_resource_directory(restobj)\n",
+ " if resource_instances:\n",
+ " #Get URI from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if \"Manager.\" in instance.Type:\n",
+ " manager_path = instance.href\n",
+ " break\n",
+ "\n",
+ " tmp = restobj.get(manager_path)\n",
+ " response = restobj.get(tmp.dict[\"links\"][\"EthernetNICs\"][\"href\"])\n",
+ "\n",
+ " for nic in response.dict[\"Items\"]:\n",
+ " if get_active and nic[\"Status\"][\"State\"] == \"Enabled\":\n",
+ " sys.stdout.write(\"Active\\t\" + nic[\"links\"][\"self\"][\"href\"] + \\\n",
+ " \": \" + json.dumps(nic) + \"\\n\")\n",
+ " elif get_active == False and nic[\"Status\"][\"State\"] == \"Disabled\":\n",
+ " sys.stdout.write(\"InActive\\t\" + nic[\"links\"][\"self\"][\"href\"] + \\\n",
+ " \": \" + json.dumps(nic) + \"\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5531c99f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " \n",
+ "This script establishes a connection to an HPE iLO server using the provided URL, login account, and password. It then logs in to the server and retrieves the NIC configuration. The script specifically fetches active NICs and displays their information. Finally, it logs out from the server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #Create a REST object\n",
+ " REST_OBJ = LegacyRestClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " REST_OBJ.login()\n",
+ " sys.stdout.write(\"\\nEXAMPLE 20: Get iLO's NIC configuration\\n\")\n",
+ " get_ilo_nic(REST_OBJ, True)\n",
+ " REST_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_PrimaryKeyServer.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_PrimaryKeyServer.ipynb
new file mode 100644
index 0000000..cf366b6
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_PrimaryKeyServer.ipynb
@@ -0,0 +1,207 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "67d9df4f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User!
\n",
+ "Welcome to
python-iLOrest-library \n",
+ "This script can be used to
manage and configure the ESKM key server for HPE iLO systems.
\n",
+ "To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ "And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7350e15b",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ " First, we are importing certain files that enable us to manage and configure the ESKM key server.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3c3347f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26b4fe53",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
Below is the set_ESKM_PrimaryKeyServer function. The function takes a Redfish client object, the primary key server address, and the primary key server port as input. It uses the Redfish API to configure the primary ESKM(Enterprise Secure Key Manager) key server on the iLO system.
\n",
+ "
It achieves this by the following steps:
\n",
+ "\n",
+ "1. It first retrieves the relevant URI for the ESKM service by either using the resource directory or by navigating through the Redfish API endpoints.
\n",
+ "The function then constructs a request body with the primary key server address and port.\n",
+ "2. It sends a POST request to the ESKM URI with the request body to update the primary key server configuration.
\n",
+ "3. If the response is successful, it displays the updated configuration in JSON format.\n",
+ "If there are any errors or exceptions, it provides appropriate error messages or status codes.
\n",
+ "4. Finally, it logs out from the iLO server.\n",
+ "
\n",
+ "The set_ESKM_PrimaryKeyServer function enables the configuration of the primary ESKM key server for HPE iLO systems. It retrieves the relevant URI, sets the primary key server address and port, and updates the configuration via a POST request. It provides feedback on the success or failure of the operation and allows for proper error handling.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5dff7bad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ESKM_PrimaryKeyServer(_redfishobj, primary_key_server_address, primary_key_server_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ "\n",
+ " body[\"PrimaryKeyServerAddress\"] = primary_key_server_address\n",
+ " body[\"PrimaryKeyServerPort\"] = int(primary_key_server_port)\n",
+ "\n",
+ " resp = _redfishobj.post(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "601ab339",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " \n",
+ "The code below establishes a connection with an iLO server using the specified system URL, login account, and password. It then sets the primary ESKM key server address and port. The script utilizes the Redfish protocol to communicate with the server and performs the necessary operations to configure the key server. Finally, it logs out from the iLO server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2cbc2d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " PRIMARY_KEY_SERVER_ADDRESS = \"192.168.1.1\"\n",
+ " PRIMARY_KEY_SERVER_PORT = \"9000\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ESKM_PrimaryKeyServer(REDFISHOBJ, PRIMARY_KEY_SERVER_ADDRESS, PRIMARY_KEY_SERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_username_pass.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_username_pass.ipynb
new file mode 100644
index 0000000..bc533d9
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ESKM_username_pass.ipynb
@@ -0,0 +1,213 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "54face1f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User!
\n",
+ "Welcome to
python-iLOrest-library \n",
+ "This script demonstrates how to
set the ESKM (Enterprise Secure Key Manager) username, password, and other related configurations for HPE iLO systems.
\n",
+ "To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ "And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7350e15b",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ " First, we are importing certain files that enable us to manage and configure the ESKM key server.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9e2d3008",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6234f26f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The code below defines a function called ESKM_username_pass that is responsible for configuring the ESKM (Enterprise Secure Key Manager) settings on an HPE iLO system using the Redfish API. The function takes several parameters, including the ESKM username, password, account group, primary key server address, and primary key server port.
\n",
+ "
The following steps explain this function:
\n",
+ "\n",
+ "1. Get the resource directory to find the URI for the ESKM service.\n",
+ "2. If the resource directory is not available or disabled, manually search for the relevant URI by navigating through the API hierarchy.\n",
+ "3. If the URI for the ESKM service is found, create a dictionary object with the login name, password, account group, ESKM local CA certificate name, primary key server address, and primary key server port.\n",
+ "4. Use the HTTP PATCH method to update the ESKM service configuration with the dictionary object.\n",
+ "5. Check the response status code to determine if the update was successful or if an error occurred. If there was an error, print the error message or status code. If the update was successful, print the response body.\n",
+ "
\n",
+ "The ESKM_username_pass function is used to configure the ESKM settings on an HPE iLO system. It retrieves the ESKM URI, populates the configuration data, sends a PATCH request to update the settings, and handles the response accordingly. Upon successful update, it prints a success message along with the response details.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38d43c16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ESKM_username_pass(_redfishobj, eskm_username, eskm_password, eskm_accountgroup, \\\n",
+ " eskm_primarykeyserver_addr, eskm_primarykeyserver_port):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " body[\"KeyManagerConfig\"] = dict()\n",
+ " body[\"KeyManagerConfig\"][\"LoginName\"] = eskm_username\n",
+ " body[\"KeyManagerConfig\"][\"Password\"] = eskm_password\n",
+ " body[\"KeyManagerConfig\"][\"AccountGroup\"] = eskm_accountgroup\n",
+ " body[\"KeyManagerConfig\"][\"ESKMLocalCACertificateName\"] = \"\"\n",
+ " body[\"PrimaryKeyServerAddress\"] = eskm_primarykeyserver_addr\n",
+ " body[\"PrimaryKeyServerPort\"] = eskm_primarykeyserver_port\n",
+ " resp = _redfishobj.patch(eskm_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "601ab339",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " \n",
+ "The code below establishes a connection with an iLO server using the specified system URL, login account, and password. It then sets the primary ESKM key server address and port. The script utilizes the Redfish protocol to communicate with the server and performs the necessary operations to configure the key server. Finally, it logs out from the iLO server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "40aabbdc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " ESKM_USERNAME = \"admin\"\n",
+ " ESKM_PASSWORD = \"password\"\n",
+ " ESKM_ACCOUNTGROUP = \"group\"\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR = \"192.168.1.10\"\n",
+ " ESKM_PRIMARYKEYSERVER_PORT = 5927\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " ESKM_username_pass(REDFISHOBJ, ESKM_USERNAME, ESKM_PASSWORD, ESKM_ACCOUNTGROUP, \\\n",
+ " ESKM_PRIMARYKEYSERVER_ADDR, ESKM_PRIMARYKEYSERVER_PORT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ethernet_management.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ethernet_management.ipynb
new file mode 100644
index 0000000..618ff4d
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ethernet_management.ipynb
@@ -0,0 +1,288 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "22c6d15e",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User!
\n",
+ "Welcome to
python-iLOrest-library \n",
+ "The objective of this script is to demonstrate how to
set the static IP configuration for the Manager ethernet interface of an HPE iLO system using the Redfish API.
\n",
+ "To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ "And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0b53f42d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ " First, we are importing certain files that can help us to manage the ethernet interface of our server.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9e2d3008",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c32f009a",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The following code defines the set_ilo_static_ipv4 function. This function is used to set the static IPv4 configuration for the Manager ethernet interface in an iLO (Integrated Lights-Out) server.
\n",
+ "\n",
+ "1. Retrieve the resource directory to find the URI for the ethernet interfaces or manually search for the relevant URI if the resource directory is disabled.\n",
+ "2. Retrieve the current configuration of the ethernet interfaces, including DHCPv4 settings, IPv4 addresses, and static name servers, and display them.\n",
+ "3. Iterate through each ethernet interface and prompt the user to choose which interface to modify.\n",
+ "4. Disable the UseDNSServers and UseGateway options if they are enabled in the DHCPv4 settings.\n",
+ "5. Update the IPv4Addresses and StaticNameServers with the provided values in the function parameters, or create a new body with the DNS servers if StaticNameServers are not available.\n",
+ "6. Send a PATCH request to update the ethernet interface configuration with the new settings.\n",
+ "Call the ilo_response function to handle the response and display any error messages or the updated configuration.\n",
+ "7. Exit the loop after processing the first ethernet interface.
\n",
+ "Overall, the function retrieves the current ethernet interface configuration, allows the user to choose which interface to modify, and updates the configuration with the provided IPv4 and DNS settings.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38d43c16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ilo_static_ipv4(_redfishobj, ipv4_dict, dns_dict):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " for interface in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Management Inteface \\'%s\\'\\n\" % ethernet_data\\\n",
+ " [interface].get('Id'))\n",
+ "\n",
+ " sys.stdout.write(\"\\'DHCPv4\\':\\n\")\n",
+ " if ethernet_data[interface].get('DHCPv4'):\n",
+ " print(json.dumps(ethernet_data[interface].get('DHCPv4'), indent=4, sort_keys=True))\n",
+ " else:\n",
+ " print(json.dumps(ethernet_data[interface]['Oem']['Hpe'].get('DHCPv4'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stdout.write(\"\\'IPv4\\':\\n\")\n",
+ " if ethernet_data[interface].get('IPv4StaticAddresses'):\n",
+ " print(json.dumps(ethernet_data[interface].get('IPv4Addresses'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ " sys.stdout.write(\"\\'StaticNameServers\\':\\n\")\n",
+ " if ethernet_data[interface].get('StaticNameServers'):\n",
+ " print(json.dumps(ethernet_data[interface].get('StaticNameServers'), indent=4, \\\n",
+ " sort_keys=True))\n",
+ "\n",
+ " for ethernet in ethernet_data:\n",
+ " sys.stdout.write(\"Ethernet Interface: %s\\n\" % ethernet)\n",
+ " ans = input(\"Would you like to modify this interface? (y/n)\\n\")\n",
+ " if \"n\" in ans:\n",
+ " continue\n",
+ " if 'DHCPv4' in ethernet_data[ethernet]:\n",
+ " if ethernet_data[ethernet]['DHCPv4'].get('UseDNSServers'):\n",
+ " resp = _redfishobj.patch(ethernet, {\"DHCPv4\": {\"UseDNSServers\": False}})\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " if ethernet_data[ethernet]['DHCPv4'].get('UseGateway'):\n",
+ " resp = _redfishobj.pathc(ethernet, {\"DHCPv4\": {\"UseGateway\": False}})\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " if 'IPv4StaticAddresses' in ethernet_data[ethernet]:\n",
+ " body.update({\"IPv4Addresses\": [ipv4_dict]})\n",
+ " if 'StaticNameServers' in ethernet_data[ethernet]:\n",
+ " body.update({\"StaticNameServers\" : [dns_dict.get('PrimaryDNS'), \\\n",
+ " dns_dict.get('SecondaryDNS')]})\n",
+ " else:\n",
+ " body.update({\"Oem\": {\"Hpe\": {\"IPv4\": {\"DNSServers\": [dns_dict.get('PrimaryDNS'), \\\n",
+ " dns_dict.get('SecondaryDNS')]}}}})\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " ilo_response(_redfishobj, resp)\n",
+ " break\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9017ca5",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ "
The following code defines the ilo_response function. This function is used to handle the response from an iLO (Integrated Lights-Out) server after sending a PATCH request to update the configuration.
\n",
+ "1. Check if the response status is 400. If it is, try to access the extended error message from the response object and print it in a formatted JSON representation.\n",
+ "2. If an exception occurs while accessing the extended error message, print a generic error message indicating that the extended message info cannot be accessed.\n",
+ "3. If the response status is not 400 (indicating an error), write a stderr message indicating the HTTP response status.\n",
+ "4. If the response status is 200 (indicating success), print a success message suggesting to reset iLO for the settings to take effect.\n",
+ "5. Print the response dictionary in a formatted JSON representation.\n",
+ "
\n",
+ "Overall, the function retrieves the current ethernet interface configuration, allows the user to choose which interface to modify, and updates the configuration with the provided IPv4 and DNS settings.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7aa4cac1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ilo_response(_redfishobj, resp):\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success! Suggest to reset iLO for settings to take effect.\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c1dc3e7f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
4.
\n",
+ " \n",
+ "Next is the main function. The code establishes a connection with a target server using Redfish, a standardized API for server management. It sets the URL, login credentials, and defines dictionaries for IPv4 and DNS settings. It creates a Redfish client object and attempts to log in using the provided credentials. If successful, it calls the set_ilo_static_ipv4 function to configure the IPv4 and DNS settings for a specific Ethernet interface on the server. The function retrieves the necessary information, displays the current settings, and prompts the user to choose an interface for modification. If selected, it updates the DHCPv4 and IPv4 static address settings based on the provided dictionaries and sends the changes to the server. Finally, the code logs out of the Redfish session.\n",
+ "
\n",
+ "In summary, the code establishes a connection with a server, configures network settings using Redfish, and performs the necessary operations to modify the IPv4 and DNS settings for a specific Ethernet interface on the server.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "40aabbdc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #IPv4 settings for Address, Gateway and SubnetMask as well as DNS.\n",
+ " IPV4_DICT = {'Address':'16.83.61.123', \\\n",
+ " 'Gateway':'16.83.60.1', \\\n",
+ " 'SubnetMask':'255.255.252.0' \\\n",
+ " }\n",
+ " DNS_DICT = {'PrimaryDNS':'16.110.135.52', \\\n",
+ " 'SecondaryDNS':'16.110.135.51' \\\n",
+ " }\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_ilo_static_ipv4(REDFISHOBJ, IPV4_DICT, DNS_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2370b35d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_ntp_servers.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_ntp_servers.ipynb
new file mode 100644
index 0000000..59c3e3a
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_ntp_servers.ipynb
@@ -0,0 +1,278 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "57e65617",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Setting NTP Servers for HPE iLO Systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "826e692d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
set the ilo NTP server! As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy, we'll be needing it in a while!\n",
+ "
\n",
+ "
Follow the guide below to execute without any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5bf83867",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library tp set up the ilo NTP server!
\n",
+ " \n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import time\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "from reset_ilo import reset_ilo\n",
+ "from enable_ntp_servers import enable_ntp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "87dd8456",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The script begins by defining the necessary dependencies and helper functions. The set_ilo_ntp_servers function is responsible for updating the NTP server settings for the iLO system.
\n",
+ "
Steps involved are:
\n",
+ "\n",
+ "\n",
+ "1. The function set_ilo_ntp_servers sets the NTP (Network Time Protocol) servers for an HPE iLO system. It first retrieves the URI for the date and time service using the get_resource_directory function. If the resource directory is disabled or not available, it finds the URI by traversing the managers' hierarchy.\n",
+ "\n",
+ "2. Once the URI is obtained, the function sends a GET request to retrieve the current NTP server settings. If the StaticNTPServers property is present, it sends a PATCH request to update the NTP server list with the provided ntp_server_list.\n",
+ "\n",
+ "3. If any error occurs during the process, the function handles it accordingly. If the response status is 400, it attempts to access the iLO extended error information and prints it. If the response status is not 200 or 400, it prints an error message.\n",
+ "\n",
+ "4. If the NTP server update is successful, it prints a success message and the updated NTP server information.\n",
+ "\n",
+ "
\n",
+ "In summary, the function retrieves the URI for the date and time service, updates the NTP server settings, and handles any errors that may occur during the process.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_ilo_ntp_servers(_redfishobj, ntp_server_list):\n",
+ "\n",
+ " date_time_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " date_time_uri = managers_members_response.obj.Oem.Hpe.Links['DateTimeService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLODateTime.' in instance['@odata.type']:\n",
+ " date_time_uri = instance['@odata.id']\n",
+ "\n",
+ " if date_time_uri:\n",
+ " data = _redfishobj.get(date_time_uri)\n",
+ " if data.dict.get('StaticNTPServers'):\n",
+ " resp = _redfishobj.patch(date_time_uri, {'StaticNTPServers': ntp_server_list})\n",
+ " else:\n",
+ " raise Exception(\"\\'StaticNTPServers\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " ntp_data = _redfishobj.get(date_time_uri).dict.get('StaticNTPServers')\n",
+ " print(\"Printing updated NTP Servers:\\n\")\n",
+ " print(json.dumps(ntp_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a12f202",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " The following code defines the give_client function, which creates a client object and performs the login operation through the following steps:
\n",
+ "1. The function give_client creates a Redfish client object by instantiating the RedfishClient class. It provides the base URL, username, and password for the Redfish service as parameters.\n",
+ "\n",
+ "2. The function attempts to log in to the Redfish service using the created client object. It sends the login request with the provided credentials.\n",
+ "\n",
+ "3. If the login is successful, the function returns the instantiated Redfish client object. If there is an error connecting to the server or if the server does not support Redfish, an error message is printed, and the program exits.\n",
+ "
\n",
+ "In summary, the give_client function creates a Redfish client object, performs the login process, and returns the client object if the login is successful.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a963c789",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def give_client():\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " rf_obj = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " rf_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " return rf_obj"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1d393dbe",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
4.
\n",
+ " This is Main function overview.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " The main section of the script sets the system URL, login account, and password. It creates a Redfish client object, logs in to the iLO system, enables NTP servers for the primary iLO management interface, resets the iLO, and waits for 60 seconds. Afterward, it logs out, creates a new Redfish client object, and calls the set_ilo_ntp_servers function to configure the NTP servers using the specified list. Finally, it logs out again.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # logfile path and filename\n",
+ " LOGFILE = input(\"Enter log file path and file name: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ahs_data(REDFISHOBJ, LOGFILE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb9dca1",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a528a3",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_timezone.ipynb b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_timezone.ipynb
new file mode 100644
index 0000000..f4fa3b7
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Shrilakshmi/set_ilo_timezone.ipynb
@@ -0,0 +1,241 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e9c3d898",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Setting the timezone for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10884361",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is a script that demonstrates how to
set the timezone for HPE iLO (Integrated Lights-Out) systems using the Redfish API.
As you are here let's get it done easily.
\n",
+ " To perform this you need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy, we'll be needing it in a while!\n",
+ "
\n",
+ "
Follow the guide below to execute without any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ef56c73",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library tp set up the ilo NTP server!
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6a1ae9ce",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
The function set_timezone is defined below. It provides a convenient way to set the timezone for an HPE iLO system using the Redfish API, utilizing the resource directory or direct URI retrieval methods to locate the relevant DateTime service and perform the timezone update.
\n",
+ "
Here's a summary of the function:
\n",
+ "\n",
+ "1.
Resource Directory Retrieval: The function retrieves the resource directory information using the _redfishobj Redfish client object. If the resource directory is not available or the DISABLE_RESOURCE_DIR flag is set, it retrieves the URI for the DateTime service from the server's Managers and Members resources.\n",
+ "\n",
+ "2.
Finding the Relevant URI: If the resource directory is available, the function searches for the relevant URI for the DateTime service within the resource instances. It looks for an instance with the '#HpeiLODateTime.' substring in its @odata.type.\n",
+ "\n",
+ "3.
Updating the Timezone: After obtaining the DateTime service URI, the function sends a GET request to retrieve the current data for the service. If the retrieved data contains the 'TimeZone' property, it constructs a JSON payload to update the timezone to the specified value. A PATCH request is then sent to the DateTime service URI with the timezone payload to modify the timezone.\n",
+ "\n",
+ "4.
Handling Responses: The function handles different response scenarios. If the response status code is 400, indicating a client-side error, it attempts to print the extended error information and the available timezone list. For response status codes other than 200 or 201, indicating an HTTP error, an appropriate error message is printed. If the response status is 200, indicating a successful update, the function prints a success message along with the updated timezone information.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_timezone(_redfishobj, timezone):\n",
+ "\n",
+ " date_time_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " date_time_uri = managers_members_response.obj.Oem.Hpe.Links['DateTimeService']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLODateTime.' in instance['@odata.type']:\n",
+ " date_time_uri = instance['@odata.id']\n",
+ "\n",
+ " if date_time_uri:\n",
+ " data = _redfishobj.get(date_time_uri)\n",
+ " if data.dict.get('TimeZone'):\n",
+ " _data = {'TimeZone': {\"Name\": timezone}}\n",
+ " resp = _redfishobj.patch(date_time_uri, _data)\n",
+ " else:\n",
+ " raise Exception(\"\\'TimeZone\\' property is not available/modifyable.\\n\")\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " print(json.dumps(data.obj.get('TimeZoneList'), indent=4, sort_keys=True))\n",
+ " sys.stderr.write(\"Check the TimeZone value...\\n\")\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " ntp_data = _redfishobj.get(date_time_uri).dict.get('TimeZone')\n",
+ " print(\"Printing updated NTP Servers:\\n\")\n",
+ " print(json.dumps(ntp_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b943b2e",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
3.
\n",
+ " This is Main function overview.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " The main section of the script proceeds to create a Redfish client object using the specified system URL, login account, and password. This client object allows communication with the remote system via Redfish APIs. After successfully creating the client object, it logs in to the system to establish an authenticated session.\n",
+ "
\n",
+ "If any server connectivity issues occur or the server does not support RedFish, an error message is displayed, and the script exits. Otherwise, the set_timezone function is called, passing the Redfish client object and the desired timezone value as parameters. This function handles the task of setting the timezone on the system using the Redfish API.\n",
+ "
\n",
+ "Upon completion, the script logs out from the system, terminating the authenticated session.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #timezone property (review the list of timezones ('TimeZoneList') within the DateTime URI.\n",
+ " TIMEZONE = \"US/Central\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_timezone(REDFISHOBJ, TIMEZONE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb9dca1",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0e4573cc",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Event log/reset_ESKM_eventlog.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Event log/reset_ESKM_eventlog.ipynb
new file mode 100644
index 0000000..6efd2a3
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Event log/reset_ESKM_eventlog.ipynb
@@ -0,0 +1,310 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7d4d890e",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reset_ESKM_eventlog"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "62aaa233",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
resetting the ESKM event log (ESKM stand for Enterprise Secure Key Manager) As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fbfec992",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish\n",
+ "
RedfishClient\n",
+ "
ServerDownOrUnreachableError\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "9b53ecf2",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ImportError",
+ "evalue": "cannot import name 'RedfishClient' from 'redfish' (/home/tanveer/.local/lib/python3.10/site-packages/redfish/__init__.py)",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01msys\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mredfish\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m RedfishClient\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mredfish\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mrest\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mv1\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ServerDownOrUnreachableError\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mget_resource_directory\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m get_resource_directory\n",
+ "\u001b[0;31mImportError\u001b[0m: cannot import name 'RedfishClient' from 'redfish' (/home/tanveer/.local/lib/python3.10/site-packages/redfish/__init__.py)"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b8c9efd9",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
2.
Below is the overview of reset_ESKM_eventlog function. In this function we are providing secure management of cryptographic keys for various purposes for example encryption and authentication.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present for secure key manager.\n",
+ "\n",
+ "1. In the function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "2. If the resource directory is enabled or we want to force it's non-use then navigate to the directory where managers members data is present. \n",
+ " Utilising the HPE (Hewlett Packard Enterprise) OEM Redfish implementation to retrieve the URI for the ESKM (Enterprise Security Key Manager) service.\n",
+ " By making a Redfish API call to reset the event log of the HPE Enterprise Secure Key Manager (ESKM) security service of an HPE server. It first tries to obtain the URI for the ESKM service using the HPE-specific resource directory, but if that is not available or disabled, it falls back to navigating the Redfish API object model to find the necessary URIs for the relevant managers and security service.\n",
+ " Once the URI for the ESKM service is obtained, a POST request is sent to the ClearESKMLog action using the post() method of the Redfish API object, with an empty dictionary in the body of the request.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "3. Else It iterates through a list of resource instances and checks if the instance type contains #HpeESKM in it. If found, it sets the URI of that resource instance as the ESKM URI and breaks out of the loop. \n",
+ " \n",
+ " \n",
+ "
\n",
+ " \n",
+ "4. If above function retrive the URI for the ESKM service from the HPE-specific Links object then we retrieves the URI for a specific action to clear the ESKM log on an HPE server's Security Service ESKM resource, using the Redfish API. It then sets the action to be executed on the server in the request body.\n",
+ " \n",
+ "
\n",
+ " \n",
+ " If the response of this POST request was 400 it means there was some error from server-side while doing the same operation and we inform the user about the error by It attempts to extract and pretty-print the extended error message information, but if this fails, it writes an error message to the standard error stream indicating that it was unable to access the iLO Extended Message Info.\n",
+ "
\n",
+ " Else there can also be an error which we aren't aware of, in that case we print out the response status code alongwith erro message .
\n",
+ " Ultimately, if everything went properly we print out the response object along with success message.\n",
+ " \n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "93003c6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_ESKM_eventlog(_redfishobj):\n",
+ "\n",
+ " body = dict()\n",
+ " security_service_eskm_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " security_service_eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " security_service_eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if security_service_eskm_uri:\n",
+ " security_service_eskm_uri = _redfishobj.get(security_service_uri).obj.Links\\\n",
+ " ['ESKM']['@odata.id']\n",
+ " security_service_eskm_resp = _redfishobj.get(security_service_eskm_uri)\n",
+ " security_service_eskm_clearlog_uri = security_service_eskm_resp.obj['Actions']\\\n",
+ " ['#HpeESKM.ClearESKMLog']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.ClearESKMLog\"\n",
+ " #We pass the URI and the dictionary as a POST command (part of the redfish object)\n",
+ " resp = _redfishobj.post(security_service_eskm_clearlog_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a583e0e",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient object is being created mainly to log into the system with valid credentials.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "3. We try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "4. Then we call reset_ESKM_eventlogfunction with our redfish object and the function does the reset the ESKM_eventlog.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "\n",
+ "5. Lastly, REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "85745d7d",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 22\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 22\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 23\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 26\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 25\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 27\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 28\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reset_ESKM_eventlog(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "69132144",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ea6fce6f",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Logical drive/get_logical_drives.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Logical drive/get_logical_drives.ipynb
new file mode 100644
index 0000000..2a78035
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Logical drive/get_logical_drives.ipynb
@@ -0,0 +1,306 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "594a0e06",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
get_logical-drives. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25be0e98",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
argparse\n",
+ "
get_resource_directory\n",
+ "
get_gen\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f16a98ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c2b4d45",
+ "metadata": {},
+ "source": [
+ "
2.
This is our get_SmartArray_LogicalDrives function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present for error free execution.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "1. The variables smartstorage_response and smartarraycontrollers are initialized as an empty list and dictionary, respectively.\n",
+ "
\n",
+ "\n",
+ "2. The get_resource_directory function is used in the code to try and retrieve the resource directory. The code resorts to a manual search for the pertinent URIs if the resource directory is unavailable or the DISABLE_RESOURCE_DIR flag is set to True.The code repeats the preceding code snippet's procedures to retrieve the pertinent URIs for smart storage and array controllers if the resource directory is not in use or unavailable.\n",
+ "
\n",
+ "\n",
+ "3. The code searches through each instance in the resource directory for instances of the specified type if the resource directory is used. It fetches the response, which is an array of array controller members, and extracts the instance's URI. After locating the first pertinent instance, the loop ends.\n",
+ "The smartstorage_response is then used by the code, presuming it contains the array of array controller elements.\n",
+ "The code obtains specific information about each controller in smartstorage_response and stores it in the smartarraycontrollers dictionary with the controller's @odata.id as the key.\n",
+ "
\n",
+ " \n",
+ "4.For the specified smart storage array controller, it prints the logical drive URIs.The code gets the logical drives URI from the controller's links, sends an HTTP GET request to get the answer, and sets the result to the logicaldrives_resp variable. \n",
+ "
\n",
+ " \n",
+ "5.The LogicalDrives key in the smartarraycontrollers dictionary is used to add the logical drive members.\n",
+ "A message is sent to stderr if there are no logical drives.\n",
+ "
\n",
+ " \n",
+ "6.The code publishes information about each logical drive in logicaldrives_resp, fetches detailed drive data with an HTTP GET request, and prints the drive data as JSON.\n",
+ "
\n",
+ " \n",
+ "7. The initial values of the variables smartarraycontrollers and smartstorage_response are a dictionary and an empty \n",
+ "list respectively.The code configures the smartstorage_uri to point to the endpoint \n",
+ "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/ for Gen9 servers. To obtain data about the array\n",
+ "controllers, use this endpoint.\n",
+ "
\n",
+ "\n",
+ "8. An HTTP GET request is sent to the smartstorage_uri, and the array of array controller members is extracted \n",
+ "from the response to populate the smartstorage_response.The code obtains specific information about each controller \n",
+ "in smartstorage_response and stores it in the smartarraycontrollers dictionary with the controller\n",
+ "@odata.id as the key.\n",
+ "
\n",
+ "9.The logical drive URIs for the specific smart storage array controller are printed by the code.The controller links, \n",
+ "specifically the LogicalDrives key under the Links object, are where the logicaldrives_uri is located.In order to \n",
+ "receive the logical drives response, which provides details about the logical drives connected to the controller, \n",
+ "the code performs an HTTP GET request to the logicaldrives_uri.\n",
+ "
\n",
+ "10.If the number of logical drive members is zero, an error message stating that no logical \n",
+ "drives are accessible for this controller is sent to stderr.Otherwise, the code publishes information about each \n",
+ "logical drive in the logicaldrives_resp, makes an HTTP GET request to the logical drive URI ,obtains detailed drive \n",
+ "data, and prints the drive data as JSON.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "95b318b7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_SmartArray_LogicalDrives_gen9(_redfishobj):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " smartstorage_uri = \"/redfish/v1/Systems/1/SmartStorage/ArrayControllers/\"\n",
+ " print (smartstorage_uri)\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Logical Drive URIs for Smart Storage Array Controller \\'%s\\' : \\n\" \\\n",
+ " % smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " logicaldrives_uri = smartarraycontrollers[controller['@odata.id']].Links\\\n",
+ " ['LogicalDrives']['@odata.id']\n",
+ " print (logicaldrives_uri)\n",
+ " logicaldrives_resp = _redfishobj.get(logicaldrives_uri)\n",
+ " if logicaldrives_resp.dict['Members@odata.count'] == 0:\n",
+ " sys.stderr.write(\"\\tLogical drives are not available for this controller.\\n\")\n",
+ " else:\n",
+ " for lds in logicaldrives_resp.dict['Members']:\n",
+ " sys.stdout.write(\"\\t An associated logical drive: %s\\n\" % logicaldrives_resp.dict['Name'])\n",
+ " drive_data = _redfishobj.get(lds['@odata.id']).dict\n",
+ " print(json.dumps(drive_data, indent=4, sort_keys=True))\n",
+ "def get_SmartArray_LogicalDrives_gen9(_redfishobj):\n",
+ "\n",
+ " smartstorage_response = []\n",
+ " smartarraycontrollers = dict()\n",
+ "\n",
+ " smartstorage_uri = \"/redfish/v1/Systems/1/SmartStorage/ArrayControllers/\"\n",
+ " print (smartstorage_uri)\n",
+ " smartstorage_response = _redfishobj.get(smartstorage_uri).obj['Members']\n",
+ "\n",
+ " for controller in smartstorage_response:\n",
+ " smartarraycontrollers[controller['@odata.id']] = _redfishobj.get(controller['@odata.id']).obj\n",
+ " sys.stdout.write(\"Logical Drive URIs for Smart Storage Array Controller \\'%s\\' : \\n\" \\\n",
+ " % smartarraycontrollers[controller['@odata.id']].get('Id'))\n",
+ " logicaldrives_uri = smartarraycontrollers[controller['@odata.id']].Links\\\n",
+ " ['LogicalDrives']['@odata.id']\n",
+ " print (logicaldrives_uri)\n",
+ " logicaldrives_resp = _redfishobj.get(logicaldrives_uri)\n",
+ " if logicaldrives_resp.dict['Members@odata.count'] == 0:\n",
+ " sys.stderr.write(\"\\tLogical drives are not available for this controller.\\n\")\n",
+ " else:\n",
+ " for lds in logicaldrives_resp.dict['Members']:\n",
+ " sys.stdout.write(\"\\t An associated logical drive: %s\\n\" % logicaldrives_resp.dict['Name'])\n",
+ " drive_data = _redfishobj.get(lds['@odata.id']).dict\n",
+ " print(json.dumps(drive_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b852d783",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: \n",
+ "
\n",
+ " - An instance of the argparse is created by the code.assigns the ArgumentParser class to the parser variable. The goal of the script is described in the description parameter.
\n",
+ " - Using the add_argument method of the ArgumentParser class, the code adds the following three command-line arguments:1.-i or --ilo: Specifies the iLO IP address of the server
2.u or --user: Indicates the iLO login username. It has the dest, action, help, and default parameters, just as the -i argument.
\n",
+ " 3.-p or --password: Specifies the iLO password for login.\n",
+ " \n",
+ " - A new variable named system_url is created and given the value \"https://\" + options.ilo_ip by the code. This creates the system's URL using the supplied iLO IP address. The iLO IP address will come after the \"https://\" in the final URL.The created URL will be shown on the console once the code outputs the system_url variable.
\n",
+ " - The DISABLE_RESOURCE_DIR option is set to False by the code. This option is used to specify whether or not the resource directory should be disabled, along with any related procedures. It is specifically set to False in this instance, allowing the resource directory to be utilised.
\n",
+ " - The base_url, username, and password that were received through the command-line inputs are passed to the code, which then creates a RedfishClient object with the name redfish_obj.The specified credentials are used to log in to the server by calling the redfish_obj.login() method. A session is established with the server as a result.A ServerDownOrUnreachableError exception is thrown if the server cannot be reached or does not support Redfish, and the script is terminated after printing an error message to stderr.
\n",
+ " - The redfish_obj is supplied as an argument when the get_gen() function is used. The server generation data is retrieved using this function.The second value of the tuple given by get_gen() is disregarded using , and the server generation is kept in the ilogen variable.The console is printed with the server generation.
\n",
+ " - The get_SmartArray_LogicalDrives() function is called with the redfish_obj parameter to obtain details on the smart array logical drives if the server generation is equal to 5, indicating a Gen5 server.\n",
+ "The get_SmartArray_LogicalDrives_gen9() function is called with the redfish_obj parameter to obtain details about the smart array logical drives unique to Gen9 servers if the server generation is not 5, indicating a different generation.
\n",
+ " - Finally logout from the session can be done by using redfish_obj.logout()
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "610979dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " # Initialize parser\n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\")\n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ "\n",
+ " options = parser.parse_args()\n",
+ "\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " get_SmartArray_LogicalDrives(redfish_obj)\n",
+ " else:\n",
+ " get_SmartArray_LogicalDrives_gen9(redfish_obj)\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80f7da07",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b5c8a5",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/ilorest_util.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/ilorest_util.ipynb
new file mode 100644
index 0000000..986d076
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/ilorest_util.ipynb
@@ -0,0 +1,183 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
ilorest_util As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "
2.
This is our get_resource_directory function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present.\n",
+ "
\n",
+ "1.Using the phrase redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id'], it attempts to retrieve the resource directory URI. The resource directory is not accessible on non-HPE servers if the key @odata.id is missing from the ResourceDirectory dictionary. Then, a message indicating the error is printed, and None is returned.\n",
+ "
\n",
+ "2.Redfishobj.get(resource_uri) is used by the code to send a GET request to the resource directory URI if it was successfully fetched.\n",
+ "
\n",
+ "3.Then we extracts the list of resource instances from the response dictionary (response.dict[\"Instances\"]) and assigns it to the resources variable if the response status is 200 (OK), which means that the resource directory was found at the specified URI (/redfish/v1/resourcedirectory).\n",
+ "
\n",
+ "4.If the response status is not 200, an error message is printed, indicating that the resource directory is missing at the specified URI.\n",
+ "
\n",
+ "5.Atlast the function return the list of resources.\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_resource_directory(redfishobj):\n",
+ "\n",
+ " try:\n",
+ " resource_uri = redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id']\n",
+ " except KeyError:\n",
+ " sys.stderr.write(\"Resource directory is only available on HPE servers.\\n\")\n",
+ " return None\n",
+ "\n",
+ " response = redfishobj.get(resource_uri)\n",
+ " resources = []\n",
+ "\n",
+ " if response.status == 200:\n",
+ " sys.stdout.write(\"\\tFound resource directory at /redfish/v1/resourcedirectory\" + \"\\n\\n\")\n",
+ " resources = response.dict[\"Instances\"]\n",
+ " else:\n",
+ " sys.stderr.write(\"\\tResource directory missing at /redfish/v1/resourcedirectory\" + \"\\n\")\n",
+ "\n",
+ " return resources"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "This is the overview of the get_gen function .\n",
+ "
\n",
+ "
\n",
+ " - It starts by accessing the root object of the Redfish API response using _redfishobj.root.obj.
\n",
+ " - Determines whether the response has the key Hpe or Hp beneath the Oem key. If so, it is assumed to be an HPE or HP server.
\n",
+ " - Based on the value of gencompany, it initialises the comp variable. Comp sets to 'Hp' if gencompany is True; otherwise, it stays None.Additionally, it looks for the key 'Hpe' under the 'Oem' key in the response. If so, it changes comp to 'Hpe'.
\n",
+ " - The code verifies whether the key ManagerType under the Manager key of the Oem dictionary is present in the response. If so, it gets the ManagerType value, which stands for the generation of the iLO.
\n",
+ " - The ManagerFirmwareVersion key is also used to access the iLO firmware version .Ilogen is set to 4 and iloversion is set to None if the iLO generation terminates in CM.
\n",
+ " - The second element is used as the iLO generation number once the iLO generation string has been divided by spaces. Additionally, it adds a dot to the final component of the iLO firmware version to create the iLO version number.
\n",
+ " - It returns a tuple (ilogen, iloversion) containing the determined iLO generation and version.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_gen(_redfishobj):\n",
+ "\trootresp = _redfishobj.root.obj\n",
+ "\t#Default iLO 5\n",
+ "\tilogen = 5\n",
+ "\tgencompany = next(iter(rootresp.get(\"Oem\", {}).keys()), None) in ('Hpe', 'Hp')\n",
+ "\tcomp = 'Hp' if gencompany else None\n",
+ "\tcomp = 'Hpe' if rootresp.get(\"Oem\", {}).get('Hpe', None) else comp\n",
+ "\tif comp and next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tget('ManagerType', None):\n",
+ "\t\tilogen = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {})))\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.get(\"ManagerType\")\n",
+ "\t\tilover = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t get(\"ManagerFirmwareVersion\")\n",
+ "\t\tif ilogen.split(' ')[-1] == \"CM\":\n",
+ "\t\t\t# Assume iLO 4 types in Moonshot\n",
+ "\t\t\tilogen = 4\n",
+ "\t\t\tiloversion = None\n",
+ "\t\telse:\n",
+ "\t\t\tilogen = ilogen.split(' ')[1]\n",
+ "\t\t\tiloversion = float(ilogen.split(' ')[-1] + '.' + \\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t''.join(ilover.split('.')))\n",
+ "\treturn (ilogen, iloversion)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "
4.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/quickstart_redfish.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/quickstart_redfish.ipynb
new file mode 100644
index 0000000..c1230f0
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Redfish utility/quickstart_redfish.ipynb
@@ -0,0 +1,168 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Quickstart_redfish"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Quickstart-redfish As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "658962be-a0df-4696-ab9e-73f844703ff9",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "53341fc4-f674-4781-bcb1-04bb06d3d1fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import redfish\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
Code overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " 1.When you are running server locally the login and password will be None.\n",
+ "
\n",
+ " 2.When server is running in remotely connect using iLO account name and iLO address then iLO host and login credentials.\n",
+ "
\n",
+ " 3.Creating redfish object which will use to communicate with the server.\n",
+ "
\n",
+ " 4.By using redfish object we can login to server and start the session.\n",
+ "
\n",
+ " 5.Next we make a http request to retrive the information about a system and printing the respone.\n",
+ "
\n",
+ " 6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# When running on the server locally use the following commented values\n",
+ "# iLO_host = \"blobstore://.\"\n",
+ "# LOGIN_ACCOUNT = \"None\"\n",
+ "# LOGIN_PASSWORD = \"None\"\n",
+ "\n",
+ "# When running remotely connect using the iLO address, iLO account name, \n",
+ "# and password to send https requests\n",
+ "iLO_host = \"https://10.0.0.100\"\n",
+ "login_account = \"admin\"\n",
+ "login_password = \"password\"\n",
+ "\n",
+ "## Create a REDFISH object\n",
+ "REDFISH_OBJ = redfish.RedfishClient(base_url=iLO_host,username=login_account, \\\n",
+ " password=login_password)\n",
+ "\n",
+ "# Login into the server and create a session\n",
+ "REDFISH_OBJ.login()\n",
+ "\n",
+ "# Do a GET on a given path\n",
+ "response = REDFISH_OBJ.get(\"/redfish/v1/systems/1\")\n",
+ "\n",
+ "# Print out the response\n",
+ "sys.stdout.write(\"%s\\n\" % response)\n",
+ "\n",
+ "# Logout of the current session\n",
+ "REDFISH_OBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0ded655-d8e4-452d-b181-783a6b1788f5",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Reset Ilo/reset_ilo.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Reset Ilo/reset_ilo.ipynb
new file mode 100644
index 0000000..a6b7d9d
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Reset Ilo/reset_ilo.ipynb
@@ -0,0 +1,267 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e2d7d850",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Resetting the Manager"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88f096f8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
Resetting the Manager As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1525f25",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
ServerDownOrUnreachableError\n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "8ce9142d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9615aea",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
This is our clear_ahs_data to function overview, in the end this will clear ahs data.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the resetting a manager function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. If the resource instance is not empty then the code fetches information about a manager from a collection of \"Managers\" resources on a target system, using a Redfish client object. It retrieves the first member's URI, and then gets more details about that specific member.\n",
+ "
\n",
+ "\n",
+ "3. Else i.e; then iterates through a collection of Redfish resource instances and checks if the type of each instance is #Manager. If it is, the code retrieves more information about that specific instance using the Redfish client object _redfishobj.\n",
+ "
\n",
+ "\n",
+ "4. If manager_members_respone is ture then it retrieves the URI for the Reset action on a specific Redfish manager using the managers_members_response variable, and then creates a request body containing the Action key with the value Manager.Reset. Finally, it sends a POSTrequest to the retrieved URI using the Redfish client object _redfishobj to initiate a reset operation on the target system.\n",
+ "
\n",
+ " 5.Next is to check the status of the response received from the previous POST request sent using the Redfish client object _redfishobj.\n",
+ "
\n",
+ " 1.If the status is 400, it attempts to print the extended error message associated with the response.\n",
+ "
\n",
+ " 2.If the response status is not 400 and not 200, an error message is printed to the standard error stream.\n",
+ "
\n",
+ " 3.If the response status is 200, it indicates that the reset operation was successful. The code then prints a success message and prints the JSON response received from the server in a formatted way.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "16042277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_ilo(_redfishobj, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " managers_members_response = None\n",
+ " \n",
+ " #function get_resource_directory returns Redfish resource instances from client object.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " #checking target resource is empty are not \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Manager.' in instance['@odata.type']:\n",
+ " managers_members_uri = instance['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " #checking the managers_members_response true or not\n",
+ " if managers_members_response:\n",
+ " reset_ilo_uri = managers_members_response.obj['Actions']['#Manager.Reset']['target']\n",
+ " body = {'Action': 'Manager.Reset'}\n",
+ " resp = _redfishobj.post(reset_ilo_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e7543eb",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call reset_ilofunction with two parameters redfish object,DISABLE_RESOURCE_DIR with our redfish object and rest the settings to default.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "270f99bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reset_ilo(REDFISHOBJ, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1557bfee",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e685a623",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/Resource directory/get_resource_directory.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/Resource directory/get_resource_directory.ipynb
new file mode 100644
index 0000000..73f4d88
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/Resource directory/get_resource_directory.ipynb
@@ -0,0 +1,234 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Get_Resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_resource_directory As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ " A redfishobj parameter is required for the function get_resource_directory. The resource directory can be retrieved using this function from a Redfish API.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. It tries to use the redfishobj object to access the resource directory URI. The server's resources are gathered in the resource directory.The server is not an HPE server and an error message is displayed to stderr if the resource directory URI cannot be discovered (KeyError is thrown). Then, the function returns null.\n",
+ "
\n",
+ " \n",
+ "2. If the resource directory URI is located, the code uses the redfishobj.get method to send an HTTP GET request to retrieve the resource directory.\n",
+ "
\n",
+ "\n",
+ "3. A response status of 200 (OK) indicates a successful retrieval of the resource directory. The function assigns the list of resource instances to the resources variable and sends a message to stdout showing the location of the resource directory.\n",
+ "
\n",
+ "\n",
+ "4. If the response status isn't 200, the resource directory is either unavailable or missing. The resources variable is empty and an error is reported to stderr.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally the function get_resource_directory return the resources.\n",
+ "
\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_resource_directory(redfishobj):\n",
+ "\n",
+ " try:\n",
+ " resource_uri = redfishobj.root.obj.Oem.Hpe.Links.ResourceDirectory['@odata.id']\n",
+ " except KeyError:\n",
+ " sys.stderr.write(\"Resource directory is only available on HPE servers.\\n\")\n",
+ " return None\n",
+ "\n",
+ " response = redfishobj.get(resource_uri)\n",
+ " resources = []\n",
+ "\n",
+ " if response.status == 200:\n",
+ " sys.stdout.write(\"\\tFound resource directory at /redfish/v1/resourcedirectory\" + \"\\n\\n\")\n",
+ " resources = response.dict[\"Instances\"]\n",
+ " else:\n",
+ " sys.stderr.write(\"\\tResource directory missing at /redfish/v1/resourcedirectory\" + \"\\n\")\n",
+ "\n",
+ " return resources\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
This is get_gen function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "\n",
+ "\n",
+ "1. The _redfishobj object, which is presumed to be a Redfish response object, is used to retrieve the root response.\n",
+ "The server generation's default setting is set to 5 (iLO 5).
\n",
+ "
\n",
+ " \n",
+ "2. By looking at the keys beneath the \"Oem\" key in the root response, it determines whether the OEM (Original Equipment Manufacturer) of the server is either \"Hpe\" or \"Hp.\" Gencompany is set to True if one of these keys is discovered; otherwise, it is set to False..
\n",
+ "
\n",
+ "\n",
+ "3. If gencompany is True, the variable comp is changed to Hp otherwise, it stays None.\n",
+ "Comp is changed to Hpe if comp is not None and the Oem key contains the subkey Hpe in the root response.
\n",
+ "
\n",
+ "\n",
+ "4. The function then accesses nested dictionaries in the root response to see if the server's manager type is present.It fetches the manager type and firmware version if the manager type is present.\n",
+ "It thinks the server is an iLO 4 type on a Moonshot system if the manager type ends with CM (probably \"Chassis Manager\") in which case it sets ilogen to 4 and iloversion to None.
\n",
+ "
\n",
+ "5. In the absence of that, it takes the management type's generation number and the firmware version number. These values are combined to create a decimal version number, which is then assigned to iloversion. Ilogen is given the extracted generation number.\n",
+ "
\n",
+ " \n",
+ "\n",
+ "6. A tuple including the server generation (ilogen) and version (iloversion) is the function's final output.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_gen(_redfishobj):\n",
+ "\trootresp = _redfishobj.root.obj\n",
+ "\t#Default iLO 5\n",
+ "\tilogen = 5\n",
+ "\tgencompany = next(iter(rootresp.get(\"Oem\", {}).keys()), None) in ('Hpe', 'Hp')\n",
+ "\tcomp = 'Hp' if gencompany else None\n",
+ "\tcomp = 'Hpe' if rootresp.get(\"Oem\", {}).get('Hpe', None) else comp\n",
+ "\tif comp and next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tget('ManagerType', None):\n",
+ "\t\tilogen = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {})))\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.get(\"ManagerType\")\n",
+ "\t\tilover = next(iter(rootresp.get(\"Oem\", {}).get(comp, {}).get(\"Manager\", {}))).\\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t get(\"ManagerFirmwareVersion\")\n",
+ "\t\tif ilogen.split(' ')[-1] == \"CM\":\n",
+ "\t\t\t# Assume iLO 4 types in Moonshot\n",
+ "\t\t\tilogen = 4\n",
+ "\t\t\tiloversion = None\n",
+ "\t\telse:\n",
+ "\t\t\tilogen = ilogen.split(' ')[1]\n",
+ "\t\t\tiloversion = float(ilogen.split(' ')[-1] + '.' + \\\n",
+ "\t\t\t\t\t\t\t\t\t\t\t''.join(ilover.split('.')))\n",
+ "\treturn (ilogen, iloversion)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/certificate/import_ssl.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/certificate/import_ssl.ipynb
new file mode 100644
index 0000000..a0c2097
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/certificate/import_ssl.ipynb
@@ -0,0 +1,257 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "4bff53aa",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Import_ssl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d4e9abe",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
importing secure socket layer As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76d83083",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - getpass
\n",
+ " - redfish
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "a54980c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5ca097d3",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2
\n",
+ "This cell gives overview about of the function SSL(secure socket layer)\n",
+ "
\n",
+ "1. It will retrieves the URI for the security service, sends a GET request to retrieve the security service object, and then retrieves the URI for the HTTPS certificate object linked to from the security service object.\n",
+ "
\n",
+ "2. Else it searches the Redfish API resource directory for an instance of a HPE HTTPS certificate object. If found, it retrieves the URI for the HTTPS certificate object and breaks out of the loop.\n",
+ "
\n",
+ "3. If the uri is not none then it retrieves the HTTPS certificate import URI from the HTTPS certificate object and then sends a POST request to import an SSL certificate using the Redfish API. The SSL certificate is passed in the request body.\n",
+ "
\n",
+ "4.Handling the error after inserting the iso image in slot \n",
+ " If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ " If status code is 200 OK then it will print error meassage and status code.\n",
+ " Else the insertion is success then code print result in JSON format and aslo printing the import is successfully done.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "d3002f22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def import_ssl(_redfishobj, ssl_file_path):\n",
+ " # intialize to None\n",
+ " https_cert_uri = None\n",
+ " body = dict()\n",
+ " #Retrieving resource directory instances using Redfish API client.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " https_cert_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " https_cert_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if https_cert_uri:\n",
+ " https_cert_import_uri = _redfishobj.get(https_cert_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.ImportCertificate']['target']\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.ImportCertificate\"\n",
+ " body[\"Certificate\"] = ssl_cert\n",
+ " resp = _redfishobj.post(https_cert_import_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\nImporting SSL Certificate may take a few minutes...\\n \"\\\n",
+ " \"iLO will reset with new changes.\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d911eb18",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3
\n",
+ "
The Main function overview . \n",
+ "
\n",
+ " - When you are running server locally or running in remotely connect using secured connection then you need to enter proper login cerdentials.
\n",
+ " - Creating redfish object and trying to establish connection with server using redfish object.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Read the content of an SSL certificate file at SSL_FILE_PATH.
\n",
+ " - Lastly, Redfishobj.logout logs us out of the system and ends the session.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4a26864f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " SSL_FILE_PATH = \"certificate.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " with open(SSL_FILE_PATH, 'r') as csr_data:\n",
+ " ssl_cert = csr_data.read()\n",
+ " csr_data.close()\n",
+ "\n",
+ " if ssl_cert:\n",
+ " import_ssl(REDFISHOBJ, ssl_cert)\n",
+ " else:\n",
+ " raise Exception(\"Invalid SSL certificate.\\n\")\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29439599",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e838742",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/index.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/index.ipynb
new file mode 100644
index 0000000..50cad6b
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/index.ipynb
@@ -0,0 +1,353 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "18ad6013",
+ "metadata": {},
+ "source": [
+ "

"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20da06d1",
+ "metadata": {},
+ "source": [
+ "
Scripts related to LOGICAL DRIVE
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fa8b0fad",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Logic drive | \n",
+ " Retrieves information about smart array logical drive | \n",
+ " GET | \n",
+ " get_logical drive | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f19c8e2c",
+ "metadata": {},
+ "source": [
+ "
Scripts related to RESOURCE DIRECTORY
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7d475db0",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Resource directory | \n",
+ " Retrieves the resource directory from an HPE server and also determines the generation and version of an iLO system | \n",
+ " GET | \n",
+ " get_resourcedirectory | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81721043",
+ "metadata": {},
+ "source": [
+ "
Scripts related to Users
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf10b943",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Delete User Account | \n",
+ " Delete user account | \n",
+ " DELETE | \n",
+ " Delete_user_ account | \n",
+ "
\n",
+ " \n",
+ " | Modify User Account | \n",
+ " Modify an iLO user account on the server | \n",
+ " GET,PATCH | \n",
+ " modify_user_ account | \n",
+ "
\n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "805abb17",
+ "metadata": {},
+ "source": [
+ "
Scripts related to Redfish Operations and Utility
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63644f9a",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Quickstart Redfish | \n",
+ " Interact with iLO using REDFISH for system information | \n",
+ " GET | \n",
+ " quickstart_redfish | \n",
+ "
\n",
+ " \n",
+ " | ilorest_util | \n",
+ " Retrieves the resource directory from the server and Determines the generation and version of the iLO | \n",
+ " GET | \n",
+ " ilorest_util | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eca287b1",
+ "metadata": {},
+ "source": [
+ "
Scripts related to SERVER
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "498b737c",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Reseting the server | \n",
+ " reset the server using the iLO API | \n",
+ " GET,POST | \n",
+ " reset_server | \n",
+ "
\n",
+ " \n",
+ " | Reboot the server | \n",
+ " reboot the server using the iLO API | \n",
+ " GET,POST | \n",
+ " reboot_server | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "22f90d0b",
+ "metadata": {},
+ "source": [
+ "
Scripts related to EVENT LOG
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "112a4521",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | reset ESKM eventlog | \n",
+ " reset the ESKM (Enterprise Secure Key Manager) event log using the iLO API | \n",
+ " POST | \n",
+ " ESKM_eventlog | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7152e64e",
+ "metadata": {},
+ "source": [
+ "
Scripts related to RESET iLO
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ad1ff043",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | reset ilo | \n",
+ " reset the ilo using the iLO API | \n",
+ " POST | \n",
+ " reset_ilo | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8f1975b",
+ "metadata": {},
+ "source": [
+ "
Scripts related to Virtual media
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7b3e6c6",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Mount virtual media | \n",
+ " mount a virtual media ISO on the iLO server | \n",
+ " GET,PATCH,POST | \n",
+ " mount_virtual_media | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b621f896",
+ "metadata": {},
+ "source": [
+ "
Scripts related to Issusing certificate
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d391db50",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " \n",
+ " \n",
+ " | OPERATION | \n",
+ " DESCRIPTION | \n",
+ " METHOD | \n",
+ " LOCATION | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | Issusing the certificate. | \n",
+ " import an SSL certificate to the iLO | \n",
+ " GET,POST | \n",
+ " import_ssl | \n",
+ "
\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reboot_server (1).ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reboot_server (1).ipynb
new file mode 100644
index 0000000..c3804bd
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reboot_server (1).ipynb
@@ -0,0 +1,236 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# REBOOTING A SERVER"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
perform rebooting of a server. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2
\n",
+ "In below cell is the reboot_server function.\n",
+ "Current cell is the overview of it, utimately at the end this will reboot the server and provide the response for the same.\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. In the
reboot server function we are first using
system_members_response variable to obtain information about the path at which server related information is stored by using couple of get requests.\n",
+ "
\n",
+ "2. If the resource directory was accessible then we simply search for
'#ComputerSystem' key (as this is the place comprising of server related information inside the
instance['odata.type'] dictionary and finally making a get request to that location.\n",
+ "
\n",
+ " \n",
+ "3. If we obtain systems_response successfully then a
ressettype list is created specifying the parameters that how we want to restart.\n",
+ " \n",
+ "\n",
+ "4. Later both the parameters are passed into a new dictionary named body and post request is created to make changes on the server side.\n",
+ " A successful
HTTP post request will set the values at server end so that a server gets rebooted.\n",
+ " \n",
+ "\n",
+ "5. Lastly, we also save response status inside
resp variable and check what is the status code returned to confirm whether the post request was success or not. If success then response by server is printed and if not then error message is printed.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reboot_server(_redfishobj):\n",
+ "\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj.get_resource_directory)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_uri = instance['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " #code check for determines whether a systems_response object is present, finds the URI for resetting a computer \n",
+ " #system, builds a request body describing the reset action and type, then sends a POST request with the provided \n",
+ " #reset type to restart the system.\n",
+ " if systems_response:\n",
+ " system_reboot_uri = systems_response.obj['Actions']['#ComputerSystem.Reset']['target']\n",
+ " body = dict()\n",
+ " resettype = ['ForceRestart','GracefulRestart']\n",
+ " body['Action'] = 'ComputerSystem.Reset'\n",
+ " for reset in resettype:\n",
+ " if reset.lower() == \"forcerestart\":\n",
+ " body['ResetType'] = \"ForceRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ " elif reset.lower() == \"gracefulrestart\":\n",
+ " body['ResetType'] = \"GracefulRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to reboot_server function to perform rebooting of server.
\n",
+ "- After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " #login credentials\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " #function call\n",
+ " reboot_server(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reset_serve.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reset_serve.ipynb
new file mode 100644
index 0000000..57d6ddc
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/server/reset_serve.ipynb
@@ -0,0 +1,306 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reset_server"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reseting the server!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ " Declared a global variable i.e; DISABLE_RESOURCE_DIR.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
RedfishClient\n",
+ "
ServerDownOrUnreachableError \n",
+ "
get_resource_directory \n",
+ "
get_gen\n",
+ " \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import argparse\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "global DISABLE_RESOURCE_DIR\n",
+ "from ilorest_util import get_resource_directory\n",
+ "from ilorest_util import get_gen\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
\n",
+ "
This is our resetting_server function overview, in the end this function the server get restarted.
\n",
+ "
Let me give you a walk through of it!
\n",
+ " 1.If either of no resource instance or DISABLE_RESOURCE_DIR flag is set then it retrieve the URI for systems from the root object, get the response for the systems URI using the Redfish API object, retrieve the URI for the members from the systems response object, and then get the response for the members URI using the Redfish API object.\n",
+ "
\n",
+ "
\n",
+ " 2.Else i.e;iterates through the resource instances, checking if the
@odata.type value contains ComputerSystem. If found, it assigns the
@odata.id value to
managers_members_uri and retrieves the response using the Redfish API object.\n",
+ "
\n",
+ "
\n",
+ " 3.This code gets the URI for the computer system reset action, builds a dictionary with an action value and reset type, iterates through reset types, then posts the body to the URI for each reset type using the Redfish API object if managers_members_response exists.\n",
+ "
\n",
+ "
\n",
+ " 4.Next is to check the status of the response received from the previous
POST request sent using the Redfish client object
_redfishobj.\n",
+ "
\n",
+ " 1.If the status is 400, it attempts to print the extended error message associated with the response.\n",
+ "
\n",
+ " 2.If the response status is not 400 and not 200, an error message is printed to the standard error stream.\n",
+ "
\n",
+ " 3.If the response status is 200, it indicates that the reset operation was successful. The code then prints a success message and prints the JSON response received from the server in a formatted way.\n",
+ "
\n",
+ "
\n",
+ " 5. Again function call
reset_server_gen9(_redfishobj) uses the Redfish API object to retrieve the response for the managers URI, the response object to retrieve the URI for the computer system reset action, etc. The action value and reset type are created in a dictionary,and the reset type is changed to
ForceRestart after printing the URI.\n",
+ "
\n",
+ " Again the
POST request sent by using RedFish client object is again checked.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_server(_redfishobj):\n",
+ " \n",
+ " managers_members_response = None\n",
+ " #Assigns resource directory to variable using Redfish API object\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " #checking if no resource instance or DISABLE_RESOURCE_DIR flag is set \n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if \"ComputerSystem.\" in instance['@odata.type']:\n",
+ " managers_members_uri = instance['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " \n",
+ " if managers_members_response:\n",
+ " path = managers_members_response.obj[\"Actions\"][\"#ComputerSystem.Reset\"][\"target\"]\n",
+ " body = dict()\n",
+ " resettype = ['ForceRestart','GracefulRestart']\n",
+ " body[\"Action\"] = \"ComputerSystem.Reset\"\n",
+ " for reset in resettype:\n",
+ " if reset.lower() == \"forcerestart\":\n",
+ " body['ResetType'] = \"ForceRestart\"\n",
+ " resp = _redfishobj.post(path, body)\n",
+ " elif reset.lower() == \"gracefulrestart\":\n",
+ " body['ResetType'] = \"GracefulRestart\"\n",
+ " resp = _redfishobj.post(path, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " \n",
+ "#creates a dictionary containing an action value and reset type, then posts the dictionary to the \n",
+ "#computer system reset action URI to reset a server using the Redfish API.\n",
+ "def reset_server_gen9(_redfishobj):\n",
+ " \n",
+ " managers_uri = \"/redfish/v1/Systems/1/\"\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " system_path = managers_response.obj[\"Actions\"][\"#ComputerSystem.Reset\"][\"target\"]\n",
+ " print(system_path)\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"Reset\"\n",
+ " body[\"ResetType\"] = \"ForceRestart\"\n",
+ "\n",
+ " resp = _redfishobj.post(system_path, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
The Main function: \n",
+ "
\n",
+ " - After initilize the parser and adds argument such as the iLO IP address, username, and password as three command-line options to the parser. Each argument has a corresponding default value and help text.
\n",
+ " - In try section of code ;utilising the supplied iLO IP address, login, and password, to create a Redfish client object. If the login is successful, the get_gen function is used to check the server generation, and based on the generation number, the proper reset method is selected. The reset_server function is called if the server is a Gen5 server; otherwise, the reset_server_gen9 function is called. An error message is printed to the console and the script terminates if the server cannot be reached or does not support Redfish.
\n",
+ " - REDFISHOBJ.logout() will take care of logging you out of the ilo.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'argparse' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;18m__name__\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__main__\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# Initialize parser \u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m parser \u001b[38;5;241m=\u001b[39m \u001b[43margparse\u001b[49m\u001b[38;5;241m.\u001b[39mArgumentParser(description \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mScript to upload and flash NVMe FW\u001b[39m\u001b[38;5;124m\"\u001b[39m) \n\u001b[1;32m 5\u001b[0m parser\u001b[38;5;241m.\u001b[39madd_argument(\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-i\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m--ilo\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 10\u001b[0m help\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miLO IP of the server\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 11\u001b[0m default\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[1;32m 12\u001b[0m parser\u001b[38;5;241m.\u001b[39madd_argument(\n\u001b[1;32m 13\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-u\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 14\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m--user\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 17\u001b[0m help\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miLO username to login\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 18\u001b[0m default\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'argparse' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # Initialize parser \n",
+ " parser = argparse.ArgumentParser(description = \"Script to upload and flash NVMe FW\") \n",
+ "\n",
+ " parser.add_argument(\n",
+ " '-i',\n",
+ " '--ilo',\n",
+ " dest='ilo_ip',\n",
+ " action=\"store\",\n",
+ " help=\"iLO IP of the server\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-u',\n",
+ " '--user',\n",
+ " dest='ilo_user',\n",
+ " action=\"store\",\n",
+ " help=\"iLO username to login\",\n",
+ " default=None)\n",
+ " parser.add_argument(\n",
+ " '-p',\n",
+ " '--password',\n",
+ " dest='ilo_pass',\n",
+ " action=\"store\",\n",
+ " help=\"iLO password to log in.\",\n",
+ " default=None)\n",
+ " #stroing namespace object in options\n",
+ " options = parser.parse_args()\n",
+ " #getting namespaceobject ilo_ip address\n",
+ " system_url = \"https://\" + options.ilo_ip\n",
+ " #printing the url obtain by ip\n",
+ " print (system_url)\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " redfish_obj = RedfishClient(base_url=system_url, username=options.ilo_user, password=options.ilo_pass)\n",
+ " # Login with the Redfish client\n",
+ " redfish_obj.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ " \n",
+ " (ilogen,_) = get_gen(redfish_obj)\n",
+ " print (\"Generation is \", ilogen)\n",
+ " if int(ilogen) == 5:\n",
+ " reset_server(redfish_obj)\n",
+ " else:\n",
+ " reset_server_gen9(redfish_obj)\n",
+ " redfish_obj.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " In case you need help 🔗 links to relevant resources :
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/account_remove.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/account_remove.ipynb
new file mode 100644
index 0000000..587c1e0
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/account_remove.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Remove iLO User Account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
a particular user account on HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "
\n",
+ "
In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ " for proper execution of our code.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of removing a user account from the HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
2.
\n",
+ "
\n",
+ " Below is the remove_ilo_user_account function, after sucessful execution of this function we will be able to delete the information of any user account that is present on the HPE iLO system.\n",
+ " \n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " \n",
+ "For removal of any general account from the system we will first have to search for the accounts that we wan't to delete based on any attribute or property that uniquely identifies the account. Upon finding that account we can just make http delete request and we are done!\n",
+ " \n",
+ "1. In the
remove_ilo_user_account function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
In case the resource directory was disabled we are navigating to the actual location where the all the member account information is stored by using
DELETErequest.\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources to obtain the
account_collection_uri.\n",
+ "
\n",
+ "4.
\n",
+ " - Now we are having the location at which all the member accounts are present.
- Simply we just find out what user account matches the account that has to be deleted based on username of the accounts.
- If we do not find the required account after completion of iteration we print out a message that required acccount was not found on the server side.
\n",
+ " - After this we simply make a DELETE request to delete that particular account and save the response obtained in resp variable.
If the http status code returned was 200, then we simply print a message that delete operation was success.
\n",
+ " Else if the status code returned was anything else we print out the status code with an error message to get idea about what went wrong.\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def remove_ilo_user_account(_redfishobj, username_to_delete):\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " #find the account to delete\n",
+ " account_uri_to_delete = None\n",
+ " account_uris = _redfishobj.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = _redfishobj.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_delete:\n",
+ " account_uri_to_delete = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_delete:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " resp = _redfishobj.delete(account_uri_to_delete)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
3.
\n",
+ "
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - The ACCOUNT_TO_DELETE contains the username of the account that we need to delete. We are passing the same as an argument while making a call to remove_ilo_user_account function.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to remove_ilo_user_account function .
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ " \n",
+ " \n",
+ " # The username of the account to remove\n",
+ " ACCOUNT_TO_DELETE = \"joker\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " remove_ilo_user_account(REDFISHOBJ, ACCOUNT_TO_DELETE)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/modify_user_account.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/modify_user_account.ipynb
new file mode 100644
index 0000000..642312c
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/user modification/modify_user_account.ipynb
@@ -0,0 +1,314 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is a example
modify_user_account. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ccd0447f",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "
2.
This is our modify_ilo_user_account function overview, in the end this will help you to modify the account.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings..\n",
+ "\n",
+ "1. In the modify_user_account function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. Retrieves the account service URI, sends a GET request to the account service, and obtains the account collection URI. If a role_id is provided, it creates a request body with the modified RoleId parameter.\n",
+ "
\n",
+ " \n",
+ "3. Else Iterate over resource instances to find the account collection URI. Modify privileges and/or login name if specified for an HPE server.\n",
+ "
\n",
+ " \n",
+ "4. If new User name is there then modified the new user name and password in the body.\n",
+ " Iterate over account URIs to find the one with a matching username. If found, modify the account using a PATCH request to the identified URI.\n",
+ "
\n",
+ " \n",
+ "5.Handling the error after inserting the iso image in slot \n",
+ "If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ "If status code is 200 OK then it will print error meassage and status code.\n",
+ "Else the modification is success then code print result in JSON format.\n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "def modify_ilo_user_account(_redfishobj, username_to_modify, new_loginname, new_username, \\\n",
+ " new_password, role_id, privilege_dict):\n",
+ "\n",
+ " account_collection_uri = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #modify role id\n",
+ " if role_id:\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " if privilege_dict:\n",
+ " #HPE server, so modify privileges\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " if new_loginname:\n",
+ " #modify login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " if new_username:\n",
+ " body[\"UserName\"] = new_username\n",
+ " if new_password:\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #find the account to modify\n",
+ " account_uri_to_modify = None\n",
+ " account_uris = REDFISHOBJ.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = REDFISHOBJ.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_modify:\n",
+ " account_uri_to_modify = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_modify:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " #modify the account by sending patch request\n",
+ " resp = REDFISHOBJ.patch(account_uri_to_modify, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER BASED WHERE YOU ARE RUUNIG THE SERVER
\n",
+ "
\n",
+ " - The variables USERNAME_TO_MODIFY, NEW_LOGINNAME, NEW_USERNAME, NEW_PASSWORD, and ROLE_ID have been assigned with the specified values.
\n",
+ " - PRIVILEGE_DICT represents a dictionary where each key corresponds to a specific privilege and the corresponding value indicates whether that privilege is enabled or disabled.
\n",
+ " - Using the redfish object we are trying to establish the connection with the server.After establish the connection we try to login .If the server is unreachable we noftify the user with error message.
\n",
+ " - If login is successful then we are calling the function with proper parameter.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "faa032c5",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 43\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 42\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 43\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, \\\n\u001b[1;32m 44\u001b[0m password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 45\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 47\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 46\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 47\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 48\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 49\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #username of the account to modify\n",
+ " USERNAME_TO_MODIFY = \"bruce_wayne\"\n",
+ "\n",
+ " #account login name to change the account to\n",
+ " NEW_LOGINNAME = \"joker\"\n",
+ "\n",
+ " #account user name to change the account to\n",
+ " NEW_USERNAME = \"joker\"\n",
+ "\n",
+ " #account password to change the account to\n",
+ " NEW_PASSWORD = \"joker123\"\n",
+ "\n",
+ " #role to change account to\n",
+ " ROLE_ID = \"ReadOnly\" #Administrator, ReadOnly or Operator are available\n",
+ "\n",
+ " #update HPE account privileges\n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": False, \"VirtualMediaPriv\": False, \"RemoteConsolePriv\": True,\\\n",
+ " \"UserConfigPriv\": False, \"VirtualPowerAndResetPriv\": False, \\\n",
+ " \"SystemRecoveryConfigPriv\": False, \"LoginPriv\": True, \\\n",
+ " \"HostStorageConfigPriv\": False, \"HostNICConfigPriv\": False, \\\n",
+ " \"HostBIOSConfigPriv\": False}\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " modify_ilo_user_account(REDFISHOBJ, USERNAME_TO_MODIFY, NEW_LOGINNAME, NEW_USERNAME, \\\n",
+ " NEW_PASSWORD, ROLE_ID, PRIVILEGE_DICT)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "
4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "
5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/HPECTY/Tanveer/virtual media/mount_virtual_media_iso.ipynb b/examples/Jupyter_notebooks/HPECTY/Tanveer/virtual media/mount_virtual_media_iso.ipynb
new file mode 100644
index 0000000..caaa955
--- /dev/null
+++ b/examples/Jupyter_notebooks/HPECTY/Tanveer/virtual media/mount_virtual_media_iso.ipynb
@@ -0,0 +1,322 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "266e8885",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Mount_virtual-media_iso"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "358b08b4",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
mount_virtual_media_iso As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "578dfc4d",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c82681e9",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/1390777471.py\u001b[0m in \u001b[0;36m
\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "84274de2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our mount_virtual-media_iso function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present.
\n",
+ "\n",
+ "1. In the change_bios_settings function we are first using resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. Retrieving information on the server's management interfaces using the Redfish API client, including members and their properties and retrieving URI for virtual media using Redfish API client.\n",
+ "
\n",
+ "\n",
+ "3. Else Using the Redfish API client and the Resource Directory, iterating through resource instances, and obtaining the URI for the virtual media collection.\n",
+ "
\n",
+ "4. If virtual_media_uri is not None then If a slot matches, the program fetches the URI for adding media into that slot and then sends a POST request to the supplied URL to insert the ISO image. Additionally, the code sends a PATCH request to set the option if a parameter is provided for the server to restart from the virtual media.\n",
+ "
\n",
+ "\n",
+ "5. Handling the error after inserting the iso image in slot \n",
+ " If status code is 400 the code attempts to retrieve and print extended error message .\n",
+ " If status code is 200 OK then it will print error meassage and status code.\n",
+ " Else the insertion is success then code print result in JSON format.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "cc680e58",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, iso_url, media_type, boot_on_next_server_reset):\n",
+ " #Initializing variables for virtual media API responses.\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "#Retrieving resource directory instances using Redfish API client.\n",
+ " resource_instances = get_resource_directory(_redfishobj)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " #retriving information Virtual media using redfish object and specified parameter\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " #iterates through each virtual media to find proper slot\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.InsertMedia']['target']\n",
+ " post_body = {\"Image\": iso_url}\n",
+ "\n",
+ " if iso_url:\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if boot_on_next_server_reset is not None:\n",
+ " patch_body = {}\n",
+ " patch_body[\"Oem\"] = {\"Hpe\": {\"BootOnNextServerReset\": \\\n",
+ " boot_on_next_server_reset}}\n",
+ " boot_resp = _redfishobj.patch(data.obj['@odata.id'], patch_body)\n",
+ " if not boot_resp.status == 200:\n",
+ " sys.stderr.write(\"Failure setting BootOnNextServerReset\")\n",
+ " #handling error after inserting iso image in slot \n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "567eb3f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ "
\n",
+ "1. If server is runnig in locally then url,login_account,Login-password will be None.\n",
+ " Else then we need to enter the proper credential.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "2. media_url will provide access and mount the iso image in server side and we initial media_type to CD.
\n",
+ "
\n",
+ "\n",
+ "3. Utilising the Redfish API to create a Redfish client object with the provided login information and log in to the server.
\n",
+ "
\n",
+ "\n",
+ "4. resolving the exception that is thrown when the server cannot be reached or does not implement the Redfish API, printing a message of error to standard error output, and terminating the program
\n",
+ "
\n",
+ "5. Using the Redfish API client object and the given arguments to mount a virtual media ISO image on a server.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "7c01d222",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Enter System URL: 120.1.114.51\n",
+ "Enter Name: tann\n",
+ "Enter password: none\n",
+ "Enter bios password: noen\n",
+ "Enter bios property you wish to change: yes\n",
+ "Enter Value of the property to change: none\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'ServerDownOrUnreachableError' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 17\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 16\u001b[0m \u001b[38;5;66;03m# Create a Redfish client object\u001b[39;00m\n\u001b[0;32m---> 17\u001b[0m REDFISHOBJ \u001b[38;5;241m=\u001b[39m \u001b[43mRedfishClient\u001b[49m(base_url\u001b[38;5;241m=\u001b[39mSYSTEM_URL, username\u001b[38;5;241m=\u001b[39mLOGIN_ACCOUNT, password\u001b[38;5;241m=\u001b[39mLOGIN_PASSWORD)\n\u001b[1;32m 19\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'RedfishClient' is not defined",
+ "\nDuring handling of the above exception, another exception occurred:\n",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 21\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[38;5;66;03m# Login with the Redfish client\u001b[39;00m\n\u001b[1;32m 20\u001b[0m REDFISHOBJ\u001b[38;5;241m.\u001b[39mlogin()\n\u001b[0;32m---> 21\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[43mServerDownOrUnreachableError\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m excp:\n\u001b[1;32m 22\u001b[0m sys\u001b[38;5;241m.\u001b[39mstderr\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mERROR: server not reachable or does not support RedFish.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 23\u001b[0m sys\u001b[38;5;241m.\u001b[39mexit()\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'ServerDownOrUnreachableError' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ " # used to access and mount iso image on server side\n",
+ " MEDIA_URL = \"http:///media.iso\"\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = \"CD\" #current possible options: Floppy, USBStick, CD, DVD\n",
+ " #specify if the server should attempt to boot this media on system restart\n",
+ " BOOT_ON_NEXT_SERVER_RESET = True\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_URL, MEDIA_TYPE, BOOT_ON_NEXT_SERVER_RESET)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9d0181a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9e9f0846",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/configure_snmp.ipynb b/examples/Jupyter_notebooks/configure_snmp.ipynb
new file mode 100644
index 0000000..32b2475
--- /dev/null
+++ b/examples/Jupyter_notebooks/configure_snmp.ipynb
@@ -0,0 +1,245 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "979defcc",
+ "metadata": {},
+ "source": [
+ "Configuring SNMP for HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "\n",
+ " Welcome to
python-iLOrest-library This is an example of
configuring SNMP for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1. Below we are importing all the necessary modules from the ilorest library.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "824911d8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "from get_resource_directory import get_resource_directory \n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "2. This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the iLO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alerts):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "3. This is Main function overview.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials are entered a redfish object is created using the input system URL, login account, and login password with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or unreachable we get server not reachable message.
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related information of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d5fe2f86",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address, account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " ALERTS_ENABLED = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_ENABLED, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/account_remove-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/account_remove-checkpoint.ipynb
new file mode 100644
index 0000000..6b07a69
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/account_remove-checkpoint.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Remove iLO User Account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
a particular user account on HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "
\n",
+ "
In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ " for proper execution of our code.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of removing a user account from the HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ "
\n",
+ " Below is the remove_ilo_user_account function, after sucessful execution of this function we will be able to delete the information of any user account that is present on the HPE iLO system.\n",
+ " \n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " \n",
+ "For removal of any general account from the system we will first have to search for the accounts that we wan't to delete based on any attribute or property that uniquely identifies the account. Upon finding that account we can just make http delete request and we are done!\n",
+ " \n",
+ "1. In the
remove_ilo_user_account function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
In case the resource directory was disabled we are navigating to the actual location where the all the member account information is stored by using
DELETErequest.\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources to obtain the
account_collection_uri.\n",
+ "
\n",
+ "4.
\n",
+ " - Now we are having the location at which all the member accounts are present.
- Simply we just find out what user account matches the account that has to be deleted based on username of the accounts.
- If we do not find the required account after completion of iteration we print out a message that required acccount was not found on the server side.
\n",
+ " - After this we simply make a DELETE request to delete that particular account and save the response obtained in resp variable.
If the http status code returned was 200, then we simply print a message that delete operation was success.
\n",
+ " Else if the status code returned was anything else we print out the status code with an error message to get idea about what went wrong.\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def remove_ilo_user_account(_redfishobj, username_to_delete):\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " #find the account to delete\n",
+ " account_uri_to_delete = None\n",
+ " account_uris = _redfishobj.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = _redfishobj.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_delete:\n",
+ " account_uri_to_delete = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_delete:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " resp = _redfishobj.delete(account_uri_to_delete)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - The ACCOUNT_TO_DELETE contains the username of the account that we need to delete. We are passing the same as an argument while making a call to remove_ilo_user_account function.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to remove_ilo_user_account function .
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ " \n",
+ " \n",
+ " # The username of the account to remove\n",
+ " ACCOUNT_TO_DELETE = \"joker\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " remove_ilo_user_account(REDFISHOBJ, ACCOUNT_TO_DELETE)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb
new file mode 100644
index 0000000..aa96161
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/bios_revert_default-checkpoint.ipynb
@@ -0,0 +1,259 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reverting the BIOS to default values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reset your bios to default settings!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "658962be-a0df-4696-ab9e-73f844703ff9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "53341fc4-f674-4781-bcb1-04bb06d3d1fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an http GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a5f7d7b2-6ab5-473d-ba19-113d603f9e2d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def bios_revert_default(_redfishobj):\n",
+ "\n",
+ " bios_reset_action_uri = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ "\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType':'default'}\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0ded655-d8e4-452d-b181-783a6b1788f5",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/change_bios_settings-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/change_bios_settings-checkpoint.ipynb
new file mode 100644
index 0000000..024bc9d
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/change_bios_settings-checkpoint.ipynb
@@ -0,0 +1,327 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "266e8885",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Change BIOS settings"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "358b08b4",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
Change BIOS settings!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "578dfc4d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c82681e9",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/1390777471.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "84274de2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our change bios settings function overview, in the end this will be able to change the bios settings.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
change_bios_settings function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an http GET request is made and response is stored in
systems_response.\n",
+ " Then we set the systems_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios data of the user through redfish object. Now we will get the bios_settings_uri through bios_data object.\n",
+ "
\n",
+ "\n",
+ "5. Then if bios password is present, then we will update the bios password. Finally we will send
patch request from redfish object using
bios_setting_uri. \n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then we will get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "cc680e58",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_bios_setting(_redfishobj, bios_property, property_value, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if bios_uri:\n",
+ " #BIOS settings URI is needed\n",
+ " \n",
+ " bios_settings_uri = bios_data.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " body = {'Attributes': {bios_property: property_value}}\n",
+ " \n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " resp = _redfishobj.patch(bios_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " #uncomment if you would like to see the full list of attributes\n",
+ " #print(\"\\n\\nShowing BIOS attributes after changes:\\n\\n\")\n",
+ " #bios_data = _redfishobj.get(bios_uri)\n",
+ " #print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "567eb3f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Please enter iLO url, username, password, bios.attribute, attribute_value,bios password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_bios_settings with our redfish object and the attribute we need and change and the value along with the bios password.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "7c01d222",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdin",
+ "output_type": "stream",
+ "text": [
+ "Enter System URL: 15.146.51.201\n",
+ "Enter Name: Administrator\n",
+ "Enter password: 12iso*help\n",
+ "Enter bios password: \n",
+ "Enter bios property you wish to change: \n",
+ "Enter Value of the property to change: \n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Initializing no proxy.\n",
+ "Redirecting 15.146.51.201/redfish/v1/ -> https://15.146.51.201/redfish/v1/\n",
+ "Response Time to /redfish/v1/: 0.5402989387512207 seconds.\n",
+ "Performing session authentication.\n",
+ "Redirecting 15.146.51.201/redfish/v1/SessionService/Sessions/ -> https://15.146.51.201/redfish/v1/SessionService/Sessions/\n",
+ "Response Time to /redfish/v1/SessionService/Sessions/: 0.11417365074157715 seconds.\n",
+ "{'@odata.context': '/redfish/v1/$metadata#Session.Session', '@odata.etag': 'W/\"793BFE96\"', '@odata.id': '/redfish/v1/SessionService/Sessions/administrator0000000062d1d61d46e97804/', '@odata.type': '#Session.v1_0_0.Session', 'Id': 'administrator0000000062d1d61d46e97804', 'Description': 'Manager User Session', 'Name': 'User Session', 'Oem': {'Hpe': {'@odata.context': '/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession', '@odata.type': '#HpeiLOSession.v2_1_0.HpeiLOSession', 'AccessTime': '2022-07-15T21:03:25Z', 'LoginTime': '2022-07-15T21:03:25Z', 'MySession': False, 'UserExpires': '2022-07-15T21:33:25Z', 'UserIP': '16.242.171.23', 'UserTag': 'REST', 'UserType': 'Local'}}, 'UserName': 'Administrator'}\n",
+ "Login returned code 201: {\"@odata.context\":\"/redfish/v1/$metadata#Session.Session\",\"@odata.etag\":\"W/\\\"793BFE96\\\"\",\"@odata.id\":\"/redfish/v1/SessionService/Sessions/administrator0000000062d1d61d46e97804/\",\"@odata.type\":\"#Session.v1_0_0.Session\",\"Id\":\"administrator0000000062d1d61d46e97804\",\"Description\":\"Manager User Session\",\"Name\":\"User Session\",\"Oem\":{\"Hpe\":{\"@odata.context\":\"/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession\",\"@odata.type\":\"#HpeiLOSession.v2_1_0.HpeiLOSession\",\"AccessTime\":\"2022-07-15T21:03:25Z\",\"LoginTime\":\"2022-07-15T21:03:25Z\",\"MySession\":false,\"UserExpires\":\"2022-07-15T21:33:25Z\",\"UserIP\":\"16.242.171.23\",\"UserTag\":\"REST\",\"UserType\":\"Local\"}},\"UserName\":\"Administrator\"}\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'get_resource_directory' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/3485138033.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 23\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 24\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 25\u001b[1;33m \u001b[0mchange_bios_setting\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mATTRIBUTE\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mATTRIBUTE_VAL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mBIOS_PASSWORD\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 26\u001b[0m \u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlogout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/2914597885.py\u001b[0m in \u001b[0;36mchange_bios_setting\u001b[1;34m(_redfishobj, bios_property, property_value, bios_password)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mbios_uri\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mbios_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mresource_instances\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_redfishobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mDISABLE_RESOURCE_DIR\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mresource_instances\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;31m#if we do not have a resource directory or want to force it's non use to find the relevant URI\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mNameError\u001b[0m: name 'get_resource_directory' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = input(\"Enter bios password: \")\n",
+ " #provide the attribute name and the associated attribute value. Note: some, values may\n",
+ " #be containers (arrays or dictionaries) so keep this in mind.\n",
+ " ATTRIBUTE = input(\"Enter bios property you wish to change: \")\n",
+ " ATTRIBUTE_VAL = input(\"Enter Value of the property to change: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_bios_setting(REDFISHOBJ, ATTRIBUTE, ATTRIBUTE_VAL, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9d0181a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9e9f0846",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/computer_details-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/computer_details-checkpoint.ipynb
new file mode 100644
index 0000000..4b81113
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/computer_details-checkpoint.ipynb
@@ -0,0 +1,237 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Gathering the computer system details"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_computer_details!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " This is our function to get the computer details requested.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
computer_details function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about computer is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the computer data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if computerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally print the Computer Details through
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def computer_details(_redfishobj):\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " print(\"\\n\\nPrinting computer system details:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter ilo url, username,password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call computer_details with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " computer_details(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/configure_snmp-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/configure_snmp-checkpoint.ipynb
new file mode 100644
index 0000000..0be3ae9
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/configure_snmp-checkpoint.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
configuring SNMP for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ccd0447f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "2.
This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings..\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alerts):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "faa032c5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " ALERTS_ENABLED = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_ENABLED, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/generate_csr-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/generate_csr-checkpoint.ipynb
new file mode 100644
index 0000000..5ed55a6
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/generate_csr-checkpoint.ipynb
@@ -0,0 +1,279 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "042acf39",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Generating a certificate signing request for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b34599c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
generate_csr!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7338dfb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0c9837f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "034daf66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our generate csr function overview, in the end we will be able to make a certificate signing request.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
generate_csr function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about Http certificates is stored inside the
managers json object.\n",
+ " And now through managers_response variable, we are making a http
GET operation to and trying to obtain the certificates of signing of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system managers members response object with different
odata_id we get a security service uri .\n",
+ " Then again an http GET request is made and response is stored in
security_service_response.\n",
+ " Then we will make a http_cert_response by using csr_uri through security_service_response and then using http_cert_response we will get
generate_csr_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeHttpsCert attribute is present in
@odata.type attribute then we'll set csr_uri and
get generate csr uri of the target.\n",
+ "
\n",
+ "\n",
+ "5. If
generate_csr_uri exists, then we will define the body and send a
post request through redfish object. After generating the csr, we can obtain the
csr_response using
get method for csr_uri.
csr_response contains
CertificateSigningRequest. \n",
+ "\n",
+ "
\n",
+ "6. If you get the result, then it is successful. if you don't get the result, then there is an error.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "644bd708",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_csr(_redfishobj, csr_file, csr_properties):\n",
+ "\n",
+ " csr_uri = None\n",
+ " generate_csr_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " csr_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " https_cert_response = _redfishobj.get(csr_uri)\n",
+ " generate_csr_uri = https_cert_response.obj['Actions']['#HpeHttpsCert.GenerateCSR']\\\n",
+ " ['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " csr_uri = instance['@odata.id']\n",
+ " generate_csr_uri = _redfishobj.get(csr_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " break\n",
+ "\n",
+ " if generate_csr_uri:\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.GenerateCSR\"\n",
+ " body[\"City\"] = csr_properties[\"City\"]\n",
+ " body[\"CommonName\"] = csr_properties[\"CommonName\"]\n",
+ " body[\"Country\"] = csr_properties[\"Country\"]\n",
+ " body[\"OrgName\"] = csr_properties[\"OrgName\"]\n",
+ " body[\"OrgUnit\"] = csr_properties[\"OrgUnit\"]\n",
+ " body[\"State\"] = csr_properties[\"State\"]\n",
+ " resp = _redfishobj.post(generate_csr_uri, body)\n",
+ " if resp.status in [200, 201]:\n",
+ " sys.stdout.write(\"Generating CSR, this may take a few minutes\\n\")\n",
+ " sys.stdout.write(\"Sleeping for 5 minutes...\\n\")\n",
+ " time.sleep(600)\n",
+ " csr_resp = _redfishobj.get(csr_uri).dict['CertificateSigningRequest']\n",
+ " with open(csr_file, 'wb') as csroutput:\n",
+ " csroutput.write(csr_resp)\n",
+ " sys.stdout.write(\"CSR Data saved to file: '%s'\\n\" % csr_file)\n",
+ " else:\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status not in [200, 201]:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2da11ba0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter your ilo url,Username,Password here.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call generate_csr with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46b3e899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #CSR Dictionary, each value should be updated to reflect the desired CSR\n",
+ " CSR_DICT = {\"City\" : input(\"Enter city:\"), \"CommonName\": input(\"Enter name:\"), \"Country\": input(\"Enter country :\"), \\\n",
+ " \"OrgName\": input(\"Enter organization :\"), \"OrgUnit\": input(\"Enter unit :\"), \"State\": input(\"Enter state:\")}\n",
+ "\n",
+ " #After CSR is generated, a file will be created and the CSR will be downloaded\n",
+ " CSR_FILE = \"csr.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " generate_csr(REDFISHOBJ, CSR_FILE, CSR_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06934cbc",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12c33902",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_bios_settings-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_bios_settings-checkpoint.ipynb
new file mode 100644
index 0000000..66d8a23
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_bios_settings-checkpoint.ipynb
@@ -0,0 +1,255 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# GETTING BIOS SETTINGS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
getting bios(basic input/output system) settings about HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ " In the beginning, we are having some import statements that are actually providing us with the required modules and libraries\n",
+ "for proper execution of our code.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of retrieving bios settings from iLO servers.\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the get_bios_settings function, after everything is done this function will give details about bios settings of system.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
get_bios_setting function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In case the resource directory was disabled we are using systems making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings.
- For that purpose simply we are making series of get requests.
\n",
+ " We make a final get operation by at the location bios_uri and save the response inside bios_data.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately, if bios_data variable is not null we print out information about bios settings. \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_bios_setting(_redfishobj):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing bios attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to get_bios_settings function to obtain information about bios settings of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdin",
+ "output_type": "stream",
+ "text": [
+ "Enter iLO IP address: 15.146.51.201\n",
+ "Enter Username: Administrator\n",
+ "Enter password: 12iso*help\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Initializing no proxy.\n",
+ "Redirecting 15.146.51.201/redfish/v1/ -> https://15.146.51.201/redfish/v1/\n",
+ "Response Time to /redfish/v1/: 0.4612421989440918 seconds.\n",
+ "Performing session authentication.\n",
+ "Redirecting 15.146.51.201/redfish/v1/SessionService/Sessions/ -> https://15.146.51.201/redfish/v1/SessionService/Sessions/\n",
+ "Response Time to /redfish/v1/SessionService/Sessions/: 0.23828959465026855 seconds.\n",
+ "{'@odata.context': '/redfish/v1/$metadata#Session.Session', '@odata.etag': 'W/\"B18A5BAF\"', '@odata.id': '/redfish/v1/SessionService/Sessions/administrator0000000062d211f0f2b02038/', '@odata.type': '#Session.v1_0_0.Session', 'Id': 'administrator0000000062d211f0f2b02038', 'Description': 'Manager User Session', 'Name': 'User Session', 'Oem': {'Hpe': {'@odata.context': '/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession', '@odata.type': '#HpeiLOSession.v2_1_0.HpeiLOSession', 'AccessTime': '2022-07-16T01:18:40Z', 'LoginTime': '2022-07-16T01:18:40Z', 'MySession': False, 'UserExpires': '2022-07-16T01:48:40Z', 'UserIP': '16.242.171.23', 'UserTag': 'REST', 'UserType': 'Local'}}, 'UserName': 'Administrator'}\n",
+ "Login returned code 201: {\"@odata.context\":\"/redfish/v1/$metadata#Session.Session\",\"@odata.etag\":\"W/\\\"B18A5BAF\\\"\",\"@odata.id\":\"/redfish/v1/SessionService/Sessions/administrator0000000062d211f0f2b02038/\",\"@odata.type\":\"#Session.v1_0_0.Session\",\"Id\":\"administrator0000000062d211f0f2b02038\",\"Description\":\"Manager User Session\",\"Name\":\"User Session\",\"Oem\":{\"Hpe\":{\"@odata.context\":\"/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession\",\"@odata.type\":\"#HpeiLOSession.v2_1_0.HpeiLOSession\",\"AccessTime\":\"2022-07-16T01:18:40Z\",\"LoginTime\":\"2022-07-16T01:18:40Z\",\"MySession\":false,\"UserExpires\":\"2022-07-16T01:48:40Z\",\"UserIP\":\"16.242.171.23\",\"UserTag\":\"REST\",\"UserType\":\"Local\"}},\"UserName\":\"Administrator\"}\n"
+ ]
+ },
+ {
+ "ename": "AttributeError",
+ "evalue": "'RedfishClient' object has no attribute 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_32988/1002653862.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 19\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 20\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m \u001b[0mget_bios_setting\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 22\u001b[0m \u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlogout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_32988/1804850166.py\u001b[0m in \u001b[0;36mget_bios_setting\u001b[1;34m(_redfishobj)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mbios_uri\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mbios_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mresource_instances\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_redfishobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_resource_directory\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_redfishobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mDISABLE_RESOURCE_DIR\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mresource_instances\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;31m#if we do not have a resource directory or want to force it's non use to find the\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mAttributeError\u001b[0m: 'RedfishClient' object has no attribute 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_bios_setting(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb
new file mode 100644
index 0000000..81c02f5
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/.ipynb_checkpoints/get_powermetrics_average-checkpoint.ipynb
@@ -0,0 +1,226 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# GETTING POWERMETRICS AVERAGE"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
get powermetrics average about HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_15656/4041776832.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of gathering the power metrics average on HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This is our powermetrics function overview, in the end this will give us with power related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. In the
get_powermetrics_average function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about power metrics is stored inside the
chassis json object.\n",
+ " Through chassis_response variable we are making a http
GET operation to and trying to obtain the power metrics about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the chassis response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
chassis_members_response.\n",
+ " The power metrics information is ultimately present in the
chassis_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if power attribute is present in
@odata.type attribute then we'll store information about power metrics in power_metrics_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if power_metrics_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to get_powermetrics_average function to obtain power related info of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/account_remove.ipynb b/examples/Jupyter_notebooks/examples/account_remove.ipynb
new file mode 100644
index 0000000..6b07a69
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/account_remove.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Remove iLO User Account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
a particular user account on HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "
\n",
+ "
In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ " for proper execution of our code.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of removing a user account from the HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ "
\n",
+ " Below is the remove_ilo_user_account function, after sucessful execution of this function we will be able to delete the information of any user account that is present on the HPE iLO system.\n",
+ " \n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " \n",
+ "For removal of any general account from the system we will first have to search for the accounts that we wan't to delete based on any attribute or property that uniquely identifies the account. Upon finding that account we can just make http delete request and we are done!\n",
+ " \n",
+ "1. In the
remove_ilo_user_account function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
In case the resource directory was disabled we are navigating to the actual location where the all the member account information is stored by using
DELETErequest.\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources to obtain the
account_collection_uri.\n",
+ "
\n",
+ "4.
\n",
+ " - Now we are having the location at which all the member accounts are present.
- Simply we just find out what user account matches the account that has to be deleted based on username of the accounts.
- If we do not find the required account after completion of iteration we print out a message that required acccount was not found on the server side.
\n",
+ " - After this we simply make a DELETE request to delete that particular account and save the response obtained in resp variable.
If the http status code returned was 200, then we simply print a message that delete operation was success.
\n",
+ " Else if the status code returned was anything else we print out the status code with an error message to get idea about what went wrong.\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def remove_ilo_user_account(_redfishobj, username_to_delete):\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " #find the account to delete\n",
+ " account_uri_to_delete = None\n",
+ " account_uris = _redfishobj.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = _redfishobj.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_delete:\n",
+ " account_uri_to_delete = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_delete:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " resp = _redfishobj.delete(account_uri_to_delete)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - The ACCOUNT_TO_DELETE contains the username of the account that we need to delete. We are passing the same as an argument while making a call to remove_ilo_user_account function.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to remove_ilo_user_account function .
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ " \n",
+ " \n",
+ " # The username of the account to remove\n",
+ " ACCOUNT_TO_DELETE = \"joker\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " remove_ilo_user_account(REDFISHOBJ, ACCOUNT_TO_DELETE)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/bios_revert_default.ipynb b/examples/Jupyter_notebooks/examples/bios_revert_default.ipynb
new file mode 100644
index 0000000..3144945
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/bios_revert_default.ipynb
@@ -0,0 +1,259 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Reverting the BIOS to default values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reset your bios to default settings!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "658962be-a0df-4696-ab9e-73f844703ff9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "53341fc4-f674-4781-bcb1-04bb06d3d1fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
This is our reset bios to default function overview, in the end this will set the bios settings to default.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
bios_revert_default function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an http GET request is made and response is stored in
bios_response.\n",
+ " Then we set the resret_action_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios settings of the user through redfish object and then then set the path to post the action we will perform\n",
+ "
\n",
+ "\n",
+ "5. Then we set the bios settings to default using the action type as
Bios.ResetBios and say set it to
default\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a5f7d7b2-6ab5-473d-ba19-113d603f9e2d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def bios_revert_default(_redfishobj):\n",
+ "\n",
+ " bios_reset_action_uri = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_response = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_response.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_reset_action_uri = bios_data.obj['Actions']['#Bios.ResetBios']['target']\n",
+ " break\n",
+ "\n",
+ " body = {'Action': 'Bios.ResetBios', 'ResetType':'default'}\n",
+ " resp = _redfishobj.post(bios_reset_action_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call bios_revert_default with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " bios_revert_default(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0ded655-d8e4-452d-b181-783a6b1788f5",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/change_bios_settings.ipynb b/examples/Jupyter_notebooks/examples/change_bios_settings.ipynb
new file mode 100644
index 0000000..024bc9d
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/change_bios_settings.ipynb
@@ -0,0 +1,327 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "266e8885",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Change BIOS settings"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "358b08b4",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
Change BIOS settings!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "578dfc4d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c82681e9",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/1390777471.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "84274de2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our change bios settings function overview, in the end this will be able to change the bios settings.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
change_bios_settings function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a bios uri .\n",
+ " Then again an http GET request is made and response is stored in
systems_response.\n",
+ " Then we set the systems_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set bios_uri and
get bios data of the user through redfish object. Now we will get the bios_settings_uri through bios_data object.\n",
+ "
\n",
+ "\n",
+ "5. Then if bios password is present, then we will update the bios password. Finally we will send
patch request from redfish object using
bios_setting_uri. \n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then we will get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "cc680e58",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def change_bios_setting(_redfishobj, bios_property, property_value, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the relevant URI\n",
+ " \n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " \n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing BIOS attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if bios_uri:\n",
+ " #BIOS settings URI is needed\n",
+ " \n",
+ " bios_settings_uri = bios_data.obj['@Redfish.Settings']['SettingsObject']['@odata.id']\n",
+ " body = {'Attributes': {bios_property: property_value}}\n",
+ " \n",
+ " #update BIOS password\n",
+ " if bios_password:\n",
+ " _redfishobj.bios_password = bios_password\n",
+ " resp = _redfishobj.patch(bios_settings_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " #uncomment if you would like to see the full list of attributes\n",
+ " #print(\"\\n\\nShowing BIOS attributes after changes:\\n\\n\")\n",
+ " #bios_data = _redfishobj.get(bios_uri)\n",
+ " #print(json.dumps(bios_data.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "567eb3f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Please enter iLO url, username, password, bios.attribute, attribute_value,bios password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call change_bios_settings with our redfish object and the attribute we need and change and the value along with the bios password.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "7c01d222",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdin",
+ "output_type": "stream",
+ "text": [
+ "Enter System URL: 15.146.51.201\n",
+ "Enter Name: Administrator\n",
+ "Enter password: 12iso*help\n",
+ "Enter bios password: \n",
+ "Enter bios property you wish to change: \n",
+ "Enter Value of the property to change: \n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Initializing no proxy.\n",
+ "Redirecting 15.146.51.201/redfish/v1/ -> https://15.146.51.201/redfish/v1/\n",
+ "Response Time to /redfish/v1/: 0.5402989387512207 seconds.\n",
+ "Performing session authentication.\n",
+ "Redirecting 15.146.51.201/redfish/v1/SessionService/Sessions/ -> https://15.146.51.201/redfish/v1/SessionService/Sessions/\n",
+ "Response Time to /redfish/v1/SessionService/Sessions/: 0.11417365074157715 seconds.\n",
+ "{'@odata.context': '/redfish/v1/$metadata#Session.Session', '@odata.etag': 'W/\"793BFE96\"', '@odata.id': '/redfish/v1/SessionService/Sessions/administrator0000000062d1d61d46e97804/', '@odata.type': '#Session.v1_0_0.Session', 'Id': 'administrator0000000062d1d61d46e97804', 'Description': 'Manager User Session', 'Name': 'User Session', 'Oem': {'Hpe': {'@odata.context': '/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession', '@odata.type': '#HpeiLOSession.v2_1_0.HpeiLOSession', 'AccessTime': '2022-07-15T21:03:25Z', 'LoginTime': '2022-07-15T21:03:25Z', 'MySession': False, 'UserExpires': '2022-07-15T21:33:25Z', 'UserIP': '16.242.171.23', 'UserTag': 'REST', 'UserType': 'Local'}}, 'UserName': 'Administrator'}\n",
+ "Login returned code 201: {\"@odata.context\":\"/redfish/v1/$metadata#Session.Session\",\"@odata.etag\":\"W/\\\"793BFE96\\\"\",\"@odata.id\":\"/redfish/v1/SessionService/Sessions/administrator0000000062d1d61d46e97804/\",\"@odata.type\":\"#Session.v1_0_0.Session\",\"Id\":\"administrator0000000062d1d61d46e97804\",\"Description\":\"Manager User Session\",\"Name\":\"User Session\",\"Oem\":{\"Hpe\":{\"@odata.context\":\"/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession\",\"@odata.type\":\"#HpeiLOSession.v2_1_0.HpeiLOSession\",\"AccessTime\":\"2022-07-15T21:03:25Z\",\"LoginTime\":\"2022-07-15T21:03:25Z\",\"MySession\":false,\"UserExpires\":\"2022-07-15T21:33:25Z\",\"UserIP\":\"16.242.171.23\",\"UserTag\":\"REST\",\"UserType\":\"Local\"}},\"UserName\":\"Administrator\"}\n"
+ ]
+ },
+ {
+ "ename": "NameError",
+ "evalue": "name 'get_resource_directory' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/3485138033.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 23\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 24\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 25\u001b[1;33m \u001b[0mchange_bios_setting\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mATTRIBUTE\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mATTRIBUTE_VAL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mBIOS_PASSWORD\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 26\u001b[0m \u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlogout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_35788/2914597885.py\u001b[0m in \u001b[0;36mchange_bios_setting\u001b[1;34m(_redfishobj, bios_property, property_value, bios_password)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mbios_uri\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mbios_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mresource_instances\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_redfishobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mDISABLE_RESOURCE_DIR\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mresource_instances\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;31m#if we do not have a resource directory or want to force it's non use to find the relevant URI\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mNameError\u001b[0m: name 'get_resource_directory' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " BIOS_PASSWORD = input(\"Enter bios password: \")\n",
+ " #provide the attribute name and the associated attribute value. Note: some, values may\n",
+ " #be containers (arrays or dictionaries) so keep this in mind.\n",
+ " ATTRIBUTE = input(\"Enter bios property you wish to change: \")\n",
+ " ATTRIBUTE_VAL = input(\"Enter Value of the property to change: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " change_bios_setting(REDFISHOBJ, ATTRIBUTE, ATTRIBUTE_VAL, BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9d0181a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9e9f0846",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/clear_ahs_data.ipynb b/examples/Jupyter_notebooks/examples/clear_ahs_data.ipynb
new file mode 100644
index 0000000..3d1f409
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/clear_ahs_data.ipynb
@@ -0,0 +1,258 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "e2d7d850",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Clearing AHS data for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88f096f8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
Clearing AHS data!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1525f25",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "8ce9142d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9615aea",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our clear_ahs_data to function overview, in the end this will clear ahs data.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
clear_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about bios is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the bios settings of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the Managers member's response object with different
odata_id we get a bios uri . Then again an http GET request is made and response is stored in
active_health_system_response.\n",
+ " Then we set the
active_health_system_clear_log_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if bios attribute is present in
@odata.type attribute then we'll set
active_health_system_uri and
get active_health_system_response settings of the user through redfish object and then then set the path to post the action of clearing ahs data we will perform\n",
+ "
\n",
+ "\n",
+ "5. We will post the
active_health_system_clear_log_uri and the body to the redfish Client through Redfish Object\n",
+ "\n",
+ " Ultimately if the operation was successfull without any errors then get the Success. If not we get the occured error.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "16042277",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ahs_data(_redfishobj):\n",
+ "\n",
+ " active_health_system_clear_log_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response.obj['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_clear_log_uri = active_health_system_response['Actions']\\\n",
+ " ['#HpeiLOActiveHealthSystem.ClearLog']['target']\n",
+ " break\n",
+ "\n",
+ " if active_health_system_clear_log_uri:\n",
+ " body = {\"Action\": \"HpeiLOActiveHealthSystem.ClearLog\"}\n",
+ " resp = _redfishobj.redfish_client.post(active_health_system_clear_log_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e7543eb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call clear_ahs_data with our redfish object and rest the settings to default.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "270f99bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ahs_data(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1557bfee",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e685a623",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/clear_ilo_iel_iml_log.ipynb b/examples/Jupyter_notebooks/examples/clear_ilo_iel_iml_log.ipynb
new file mode 100644
index 0000000..0bf7897
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/clear_ilo_iel_iml_log.ipynb
@@ -0,0 +1,230 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# CLEAR iLO LOGS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
for clearing out the ilo event log and management log at server side!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2
\n",
+ "This cell gives overview about of the function used to clear event logs such as IML and IEL logs. \n",
+ "The IML provides a record of historical events that have occurred on the server and the IEL is the iLO event log provides record of significant events detected by iLO.\n",
+ " \n",
+ "1. When the resource directory is disabled then we simply navigate through the API for obtaining the relevant uri.\n",
+ " The series of HTTP get requests aims to extracts log_services_response so as to get the path of the directory for which IEL and IML logs need to be cleared.\n",
+ "
\n",
+ "2. Else if the resource directory enabled then rather we can simply extract the uri by #LogService.attribute inside the instance['odatatype'] dictionary and again make a HTTP get request to obtain the required uri.\n",
+ "
\n",
+ "3. After obtaining the uri we just need to make changes on the same location using a post request so as to clear IEL and IML logs successfully. For this body dictionary contains the attribute to be changed and IEL/IML are searched in the path of clear_log_services_uri and the respective changes are made by redfishobj.post(path,body).\n",
+ "
\n",
+ " \n",
+ "4. Later we also check for the response returned by the server side. If the response is anything outside of status code with 200 then error message gets rendered on the webpage else the success message is printed out with the response dictionary returned by the server.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def clear_ilo_event_log(_redfishobj, clear_IML_IEL):\n",
+ "\n",
+ " clear_log_services_uri = []\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " log_services_uri = systems_members_response.obj['LogServices']['@odata.id']\n",
+ " log_services_response = _redfishobj.get(log_services_uri)\n",
+ " log_services_uris = log_services_response.obj['Members']\n",
+ " for log_services_uri in log_services_uris:\n",
+ " log_services_response = _redfishobj.get(log_services_uri['@odata.id'])\n",
+ " clear_log_services_uri.append(log_services_response.obj['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#LogService.' in instance['@odata.type']:\n",
+ " log_service_uri = instance['@odata.id']\n",
+ " clear_log_services_uri.append(_redfishobj.get(log_service_uri).dict['Actions']\\\n",
+ " ['#LogService.ClearLog']['target'])\n",
+ "\n",
+ " if clear_log_services_uri:\n",
+ " body = {\"Action\": \"LogService.ClearLog\"}\n",
+ " for path in clear_log_services_uri:\n",
+ " if (\"IEL\" in clear_IML_IEL and \"IEL\" in path) or (\"IML\" in clear_IML_IEL and \\\n",
+ " \"IML\" in path):\n",
+ " if \"IEL\" in path:\n",
+ " sys.stdout.write(\"Clearing IEL log.\\n\")\n",
+ " else:\n",
+ " sys.stdout.write(\"Clearing IML log.\\n\")\n",
+ " resp = _redfishobj.post(path, body)\n",
+ " else:\n",
+ " continue\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Else if no error is encountered a function call is made i.e. clear_ilo_event_log(REDFISHOBJ, CLEAR_IEL_IML)\n",
+ " that is responsible for handling clearing all the IEL and IML logs at the server side.
.\n",
+ " - Lastly, Redfishobj.logout logs us out of the system and ends the session.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ " CLEAR_IML_IEL = \"IML\" # provide either the string IML or IEL\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " clear_ilo_event_log(REDFISHOBJ, CLEAR_IML_IEL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/computer_details.ipynb b/examples/Jupyter_notebooks/examples/computer_details.ipynb
new file mode 100644
index 0000000..4b81113
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/computer_details.ipynb
@@ -0,0 +1,237 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a38bafdc",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Gathering the computer system details"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfe2e2b6",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_computer_details!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b3fec1a9",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "ab7125e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d23d990",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " This is our function to get the computer details requested.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
computer_details function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about computer is stored inside the
systems json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the computer data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system members response object with different
odata_id we get a system uri .\n",
+ " Then again an http GET request is made and response is stored in
system_response.\n",
+ " Then we set the system_members_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if computerSystem attribute is present in
@odata.type attribute then we'll set
systems_members_uri and
get systems_members_response of the user through redfish object.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "5. Finally print the Computer Details through
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1b4d0494",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def computer_details(_redfishobj):\n",
+ " systems_members_uri = None\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_members_uri = instance['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ "\n",
+ " print(\"\\n\\nPrinting computer system details:\\n\\n\")\n",
+ " print(json.dumps(systems_members_response.dict, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0de7de8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter ilo url, username,password
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call computer_details with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3f538059",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " \n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " computer_details(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd337e8f",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7fd2c36",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/configure_snmp.ipynb b/examples/Jupyter_notebooks/examples/configure_snmp.ipynb
new file mode 100644
index 0000000..0be3ae9
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/configure_snmp.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a127fdb8",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
configuring SNMP for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cf44a38",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ccd0447f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c988b347",
+ "metadata": {},
+ "source": [
+ "2.
This is our configure_snmp function overview, in the end this will give us with snmp configure related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings..\n",
+ "\n",
+ "1. In the
configure_snmp function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3804eab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def configure_snmp(_redfishobj, read_communities, snmp_alerts):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['Snmp']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#HpeiLOSnmpService.' in instance['@odata.type']:\n",
+ " snmp_service_uri = instance['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " body = {\"AlertsEnabled\": snmp_alerts, \"ReadCommunities\": read_communities}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e047370",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "faa032c5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #Properties:\n",
+ " #read communities array\n",
+ " READ_COMMUNITIES = [\"public\", \"\", \"\"]\n",
+ " #alerts_enabled primitive (boolean)\n",
+ " ALERTS_ENABLED = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ, READ_COMMUNITIES, ALERTS_ENABLED, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "337fd6f7",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a45c7e01",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/configure_snmp_trap_source.ipynb b/examples/Jupyter_notebooks/examples/configure_snmp_trap_source.ipynb
new file mode 100644
index 0000000..3418e6b
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/configure_snmp_trap_source.ipynb
@@ -0,0 +1,220 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "594a0e06",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
configuring SNMP trap source for HPE iLO systems. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "25be0e98",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f16a98ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c2b4d45",
+ "metadata": {},
+ "source": [
+ "2.
This is our configure_snmp function overview, in the end this will give us with snmp service related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the snmp service information.\n",
+ "\n",
+ " \n",
+ "\n",
+ " \n",
+ "1. In the ILO rest api the information about snmp is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the snmp about iLO system.\n",
+ "
\n",
+ "\n",
+ "2. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The snmp configuration information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if power snmp is present in
@odata.type attribute then we will store information about snmp in snmp_service_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if snmp_service_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b53e8e73",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ " def configure_snmp(_redfishobj):\n",
+ "\n",
+ " snmp_service_uri = None\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " # print(managers_members_response.obj['Oem']['Hpe']['Links'])\n",
+ " # exit(0)\n",
+ " snmp_service_uri = managers_members_response.obj.Oem.Hpe.Links['SNMPService']['@odata.id']\n",
+ "\n",
+ " if snmp_service_uri:\n",
+ " # resp = _redfishobj.get(snmp_service_uri)\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " # exit(0)\n",
+ " # TrapSourceHostname : Manager or System\n",
+ " body = {\"TrapSourceHostname\": \"System\"}\n",
+ " resp = _redfishobj.patch(snmp_service_uri, body)\n",
+ "\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4,\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " # print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b852d783",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to configure_snmp function to obtain snmp related info of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "610979dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " if len(sys.argv) <= 3:\n",
+ " sys.stderr.write(\"ERROR: We need 3 arguments. \\nUsage: change-snmp.py \"\n",
+ " \"ILOIPADDR ILOUSER ILOPASSWORD \\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " SYSTEM_URL = \"https://\" + sys.argv[1]\n",
+ " LOGIN_ACCOUNT = sys.argv[2]\n",
+ " LOGIN_PASSWORD = sys.argv[3]\n",
+ "\n",
+ " try:\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT,\n",
+ " password=LOGIN_PASSWORD)\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " configure_snmp(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "80f7da07",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00b5c8a5",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/eject_virtual_media_iso.ipynb b/examples/Jupyter_notebooks/examples/eject_virtual_media_iso.ipynb
new file mode 100644
index 0000000..fbd4918
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/eject_virtual_media_iso.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "45dd47a5",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
mounting virtual media for HPE iLO systems As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23eeb2bf",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92ec68a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a8e977",
+ "metadata": {},
+ "source": [
+ "2.
This is our mount_virtual_media_iso function overview, in the end this will give us with virtual media related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the virtual media information.\n",
+ "\n",
+ "1. In the
mount_virtual_media_iso function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about virtual media is stored inside the
managers json object.\n",
+ " Through managers_response variable we are making a http
GET operation to and trying to obtain the virtual media about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
managers_members_response.\n",
+ " The virtual media information is ultimately present in the
managers_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if virtual media is present in
@odata.type attribute then we will store information about virtual media in virtual_media_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if virtual_media_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f034ef9c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def mount_virtual_media_iso(_redfishobj, media_type,):\n",
+ "\n",
+ " virtual_media_uri = None\n",
+ " virtual_media_response = []\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " virtual_media_uri = managers_members_response.obj['VirtualMedia']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#VirtualMediaCollection.' in instance['@odata.type']:\n",
+ " virtual_media_uri = instance['@odata.id']\n",
+ "\n",
+ " if virtual_media_uri:\n",
+ " virtual_media_response = _redfishobj.get(virtual_media_uri)\n",
+ " for virtual_media_slot in virtual_media_response.obj['Members']:\n",
+ " data = _redfishobj.get(virtual_media_slot['@odata.id'])\n",
+ " if media_type in data.dict['MediaTypes']:\n",
+ " virtual_media_mount_uri = data.obj['Actions']['#VirtualMedia.EjectMedia']['target']\n",
+ " post_body = {\"Action\": \"HpeiLOVirtualMedia.EjectVirtualMedia\"}\n",
+ " resp = _redfishobj.post(virtual_media_mount_uri, post_body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO\"\n",
+ " \"Extended Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "268b5a18",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to mount_virtual_media_iso to obtain virtual media related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ab494baf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #specify the type of content the media represents\n",
+ " MEDIA_TYPE = \"CD\" #current possible options: Floppy, USBStick, CD, DVD\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ "\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " mount_virtual_media_iso(REDFISHOBJ, MEDIA_TYPE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90621a8a",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a839daaa",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/enable_secure_boot.ipynb b/examples/Jupyter_notebooks/examples/enable_secure_boot.ipynb
new file mode 100644
index 0000000..9760b1d
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/enable_secure_boot.ipynb
@@ -0,0 +1,249 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b44c9aad",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is an example of
enabling secure boot As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "74ee46a2",
+ "metadata": {},
+ "source": [
+ " \n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3b9ca27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0e073c6",
+ "metadata": {},
+ "source": [
+ "2.
This is our enable_secure_boot function overview, in the end this will give us with secure boot related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ "There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the secure boot information.\n",
+ "\n",
+ "1. In the
enable_secure_boot function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about secureboot is stored inside the
systems json object.\n",
+ " Through systems_response variable we are making a http
GET operation to and trying to obtain the secure boot about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the systems response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
systems_members_response.\n",
+ " The secure boot information is ultimately present in the
systems_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if secure boot is present in
@odata.type attribute then we will store information about secure boot in secure_boot_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if secure_boot_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8d60549e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_secure_boot(_redfishobj, secure_boot_enable):\n",
+ "\n",
+ " secure_boot_uri = None\n",
+ " secure_boot_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " secure_boot_uri = systems_members_response.obj['SecureBoot']['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#SecureBoot.' in instance['@odata.type']:\n",
+ " secure_boot_uri = instance['@odata.id']\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ "\n",
+ " if secure_boot_data:\n",
+ " print(\"\\n\\nShowing Secure Boot properties before changes:\\n\\n\")\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))\n",
+ "\n",
+ " if secure_boot_uri:\n",
+ " body = {'SecureBootEnable': secure_boot_enable}\n",
+ " resp = _redfishobj.patch(secure_boot_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \" \\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"\\nSuccess!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " print(\"\\n\\nShowing Secure Boot properties after changes:\\n\\n\")\n",
+ " secure_boot_data = _redfishobj.get(secure_boot_uri)\n",
+ " print(json.dumps(secure_boot_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b227f8f6",
+ "metadata": {},
+ "source": [
+ "3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to enable_secure_boot function to obtain secure boot related info of system.
\n",
+ " - After getting required information Redfish.logout() closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8028b4ff",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " #Properties:\n",
+ " #secure boot enable property\n",
+ " SECURE_BOOT_ENABLE = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_secure_boot(REDFISHOBJ, SECURE_BOOT_ENABLE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28cb201c",
+ "metadata": {},
+ "source": [
+ "4.
\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf8a164b",
+ "metadata": {},
+ "source": [
+ "5.
In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/enabling_ntp_server.ipynb b/examples/Jupyter_notebooks/examples/enabling_ntp_server.ipynb
new file mode 100644
index 0000000..12cd454
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/enabling_ntp_server.ipynb
@@ -0,0 +1,246 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# ENABLING NTP SERVER "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
enable ntp servers . As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2
\n",
+ "Below function describes the process how to enable NTP servers for HPE ilo systems. NTP or Network Time Protocol is an internet protocol used to synchronize with computer clokc time sources in a network. \n",
+ "Current cell is the explains the processes performed inside the below function.\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. Initially, to obtain NTP server related information for HPE ilo systems a series of HTTP GET requests are being made so as to navigate to that path inside the iLO rest api where required information is stored.\n",
+ "After completion of these get requests we will be having the relevant uri in
manager_ethernet_interfaces_members.\n",
+ "
\n",
+ "2. Else if
resource directory is enabled we can just use the resource directory to and then again navigate through the api to find relevant uri.\n",
+ "
\n",
+ " \n",
+ "3. Whatever changes need to be made to enable the NTP server are being enclosed inside the dictionary named as
body. Next up for all the instances of ethernet in ethernet_data we simply make a
HTTP PATCH request by passing the ethernet instance and body dictionary with the PATCH request. \n",
+ " \n",
+ "\n",
+ "4. Following the patch request, the response returned by server is being saved inside resp variable and later if the server returns proper response it means there is no error else error is returned with error information. A reference for json.dumps\n",
+ "function as it is used multiple times -
click here.\n",
+ "\n",
+ "\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def enable_ntp(_redfishobj, ntp_servers, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " break\n",
+ "\n",
+ " if ethernet_data:\n",
+ " print(\"\\n\\nShowing all available ethernet management interfaces before changes:\\n\\n\")\n",
+ " print(json.dumps(ethernet_data, indent=4, sort_keys=True))\n",
+ "\n",
+ " body = {\"Oem\": {\"Hpe\": {\"DHCPv4\": {\"UseNTPServers\": ntp_servers}, \\\n",
+ " \"DHCPv6\": {\"UseNTPServers\": ntp_servers}}}}\n",
+ " for ethernet in ethernet_data:\n",
+ " resp = _redfishobj.patch(ethernet, body)\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))\n",
+ " _data = _redfishobj.get(ethernet).dict\n",
+ " sys.stdout.write(\"\\nShowing \\'%s\\' interface after changes:\\n\" % ethernet)\n",
+ " print(json.dumps(_data, indent=4, sort_keys=True))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to enable_ntp function by passing parameters such as redfishclient object and enable flag to perform required operation.
\n",
+ "- After getting required information Redfish.logout() closes the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # Properties\n",
+ " # NTP Servers Enable/Disable Flag\n",
+ " NTP_SERVERS = True\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " enable_ntp(REDFISHOBJ, NTP_SERVERS, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/find_ilo_mac_address.ipynb b/examples/Jupyter_notebooks/examples/find_ilo_mac_address.ipynb
new file mode 100644
index 0000000..0fcb8d3
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/find_ilo_mac_address.ipynb
@@ -0,0 +1,227 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Finding iLo Mac address"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
find_ilo_mac_address!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This is our find_ilo_mac_address function overview, in the end this will give us about finding ilo mac address related information.
\n",
+ "
Let me give you a walk through of it!
\n",
+ "
\n",
+ " - For the identification of a device, its mac address is very much required. If you have the Systems Management Homepage installed, you can find out by clicking \"Management Processor\" and then check the Physical Address field.
\n",
+ " - If we don't have a resource directory, information about the ethernet data is stored inside the managers json object. Through managers_response variable we are making a http GET operation to and trying to obtain the virtual media about iLO system.
\n",
+ " - Ethernet interface gives the response for that member about the ilo mac address
\n",
+ " - If the resource directory is present, then we will simply iterate through all instances inside resources and if the ethernet interface is present in @odata.type attribute then we will store information about ethernet interface in ethernet_data dictionary and break out of iteration.
\n",
+ " - Finally, we get iLo Network Manager Interface and iLO Mac Address as output.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_ilo_mac_address(_redfishobj):\n",
+ "\n",
+ " ethernet_data = {}\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " manager_ethernet_interfaces = managers_members_response.obj['EthernetInterfaces']\\\n",
+ " ['@odata.id']\n",
+ " manager_ethernet_interfaces_response = _redfishobj.get(manager_ethernet_interfaces)\n",
+ " manager_ethernet_interfaces_members = manager_ethernet_interfaces_response.\\\n",
+ " obj['Members']\n",
+ " for _member in manager_ethernet_interfaces_members:\n",
+ " _tmp = _redfishobj.get(_member['@odata.id']).obj\n",
+ " ethernet_data[_member['@odata.id']] = _tmp\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#EthernetInterfaceCollection.' in instance['@odata.type'] and 'Managers' in \\\n",
+ " instance['@odata.id']:\n",
+ " ethernet_uri = instance['@odata.id']\n",
+ " ethernet_interfaces = _redfishobj.get(ethernet_uri).obj['Members']\n",
+ " for _ethernet_interface in ethernet_interfaces:\n",
+ " ethernet_data[_ethernet_interface['@odata.id']] = _redfishobj.\\\n",
+ " get(_ethernet_interface['@odata.id']).dict\n",
+ " for iface in ethernet_data:\n",
+ " sys.stdout.write(\"iLO Network Manager Interface: \\'%s\\'\\n\" % ethernet_data[iface]['Id'])\n",
+ " sys.stdout.write(\"\\tiLO Mac Address: \\'%s\\'\\n\" % ethernet_data[iface].get('MACAddress'))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get \"server not reachable\" message!
\n",
+ " - and Once everything is done you are automatically logged out with .logout() 😁.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " find_ilo_mac_address(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/generate_csr.ipynb b/examples/Jupyter_notebooks/examples/generate_csr.ipynb
new file mode 100644
index 0000000..5ed55a6
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/generate_csr.ipynb
@@ -0,0 +1,279 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "042acf39",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Generating a certificate signing request for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7b34599c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
generate_csr!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7338dfb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0c9837f2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "034daf66",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
This is our generate csr function overview, in the end we will be able to make a certificate signing request.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
generate_csr function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about Http certificates is stored inside the
managers json object.\n",
+ " And now through managers_response variable, we are making a http
GET operation to and trying to obtain the certificates of signing of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the system managers members response object with different
odata_id we get a security service uri .\n",
+ " Then again an http GET request is made and response is stored in
security_service_response.\n",
+ " Then we will make a http_cert_response by using csr_uri through security_service_response and then using http_cert_response we will get
generate_csr_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeHttpsCert attribute is present in
@odata.type attribute then we'll set csr_uri and
get generate csr uri of the target.\n",
+ "
\n",
+ "\n",
+ "5. If
generate_csr_uri exists, then we will define the body and send a
post request through redfish object. After generating the csr, we can obtain the
csr_response using
get method for csr_uri.
csr_response contains
CertificateSigningRequest. \n",
+ "\n",
+ "
\n",
+ "6. If you get the result, then it is successful. if you don't get the result, then there is an error.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "644bd708",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_csr(_redfishobj, csr_file, csr_properties):\n",
+ "\n",
+ " csr_uri = None\n",
+ " generate_csr_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['SecurityService']['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " csr_uri = security_service_response.obj.Links['HttpsCert']['@odata.id']\n",
+ " https_cert_response = _redfishobj.get(csr_uri)\n",
+ " generate_csr_uri = https_cert_response.obj['Actions']['#HpeHttpsCert.GenerateCSR']\\\n",
+ " ['target']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeHttpsCert.' in instance['@odata.type']:\n",
+ " csr_uri = instance['@odata.id']\n",
+ " generate_csr_uri = _redfishobj.get(csr_uri).obj['Actions']\\\n",
+ " ['#HpeHttpsCert.GenerateCSR']['target']\n",
+ " break\n",
+ "\n",
+ " if generate_csr_uri:\n",
+ " body = dict()\n",
+ " body[\"Action\"] = \"HpeHttpsCert.GenerateCSR\"\n",
+ " body[\"City\"] = csr_properties[\"City\"]\n",
+ " body[\"CommonName\"] = csr_properties[\"CommonName\"]\n",
+ " body[\"Country\"] = csr_properties[\"Country\"]\n",
+ " body[\"OrgName\"] = csr_properties[\"OrgName\"]\n",
+ " body[\"OrgUnit\"] = csr_properties[\"OrgUnit\"]\n",
+ " body[\"State\"] = csr_properties[\"State\"]\n",
+ " resp = _redfishobj.post(generate_csr_uri, body)\n",
+ " if resp.status in [200, 201]:\n",
+ " sys.stdout.write(\"Generating CSR, this may take a few minutes\\n\")\n",
+ " sys.stdout.write(\"Sleeping for 5 minutes...\\n\")\n",
+ " time.sleep(600)\n",
+ " csr_resp = _redfishobj.get(csr_uri).dict['CertificateSigningRequest']\n",
+ " with open(csr_file, 'wb') as csroutput:\n",
+ " csroutput.write(csr_resp)\n",
+ " sys.stdout.write(\"CSR Data saved to file: '%s'\\n\" % csr_file)\n",
+ " else:\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended\n",
+ " #info error message to see what went wrong\n",
+ " if resp.status not in [200, 201]:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO \"\\\n",
+ " \"Extended Message Info...\\n\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2da11ba0",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter your ilo url,Username,Password here.
\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call generate_csr with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46b3e899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #CSR Dictionary, each value should be updated to reflect the desired CSR\n",
+ " CSR_DICT = {\"City\" : input(\"Enter city:\"), \"CommonName\": input(\"Enter name:\"), \"Country\": input(\"Enter country :\"), \\\n",
+ " \"OrgName\": input(\"Enter organization :\"), \"OrgUnit\": input(\"Enter unit :\"), \"State\": input(\"Enter state:\")}\n",
+ "\n",
+ " #After CSR is generated, a file will be created and the CSR will be downloaded\n",
+ " CSR_FILE = \"csr.txt\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " generate_csr(REDFISHOBJ, CSR_FILE, CSR_DICT)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "06934cbc",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12c33902",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/get_ahs_data.ipynb b/examples/Jupyter_notebooks/examples/get_ahs_data.ipynb
new file mode 100644
index 0000000..2115568
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/get_ahs_data.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a597eefb",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Gathering AHS data for HPE iLO systems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6b03740b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
get_ahs_data!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45944a06",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ "
get_resource_directory\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c329cde9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29082d3a",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
This is our ahs gathering data function overview, in the end we will get the Active Health System data.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.
\n",
+ "\n",
+ "1. In the
get_ahs_data function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about the Active Health System is stored inside the
managers json object.\n",
+ " And now through system_response variable, we are making a http
GET operation to and trying to obtain the ahs data of iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the managers response object with different
odata_id we get the managers members uri .\n",
+ " Then again an http GET request is made and response is stored in
managers_response_response.\n",
+ " Then we set the
active_health_system_uri.\n",
+ "
\n",
+ "\n",
+ "4. Else i.e; resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if HpeiLOActiveHealthSystem attribute is present in
@odata.type attribute then we'll set active_health_system_uri and
get active_health_system_log_resp through redfish object.\n",
+ "
\n",
+ "\n",
+ "5. If this is successful, then we will open a
logfile and write
active_health_system_log_resp.ori which is the get_ahs_data to that logfile.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f3786dd7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_ahs_data(_redfishobj, logfile=\"data.ahs\"):\n",
+ "\n",
+ " active_health_system_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " active_health_system_uri = managers_members_response.obj.Oem.Hpe.Links\\\n",
+ " ['ActiveHealthSystem']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeiLOActiveHealthSystem.' in instance['@odata.type']:\n",
+ " active_health_system_uri = instance['@odata.id']\n",
+ "\n",
+ " if active_health_system_uri:\n",
+ " active_health_system_response = _redfishobj.get(active_health_system_uri)\n",
+ " active_health_system_log_uri = active_health_system_response.obj.Links['AHSLocation']\\\n",
+ " ['extref']\n",
+ " active_health_system_log_resp = _redfishobj.get(active_health_system_log_uri)\n",
+ " if active_health_system_log_resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(active_health_system_log_resp.obj['error']\\\n",
+ " ['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif active_health_system_log_resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % active_health_system_log_resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " with open(logfile, 'wb') as ahsoutput:\n",
+ " ahsoutput.write(active_health_system_log_resp.ori)\n",
+ " ahsoutput.close()\n",
+ " sys.stdout.write(\"AHS Data saved successfully as: \\'%s\\'\" % logfile)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "155fb958",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " Enter ilo url,username,password, and the path of log file
\n",
+ " \n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username,Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. ow we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_ahs_data with our redfish object and logfile.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e3f7743a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # logfile path and filename\n",
+ " LOGFILE = input(\"Enter log file path and file name: \")\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_ahs_data(REDFISHOBJ, LOGFILE)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb9dca1",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " LOGFILE = data.ahs
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10a528a3",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/get_bios_settings.ipynb b/examples/Jupyter_notebooks/examples/get_bios_settings.ipynb
new file mode 100644
index 0000000..66d8a23
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/get_bios_settings.ipynb
@@ -0,0 +1,255 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# GETTING BIOS SETTINGS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
getting bios(basic input/output system) settings about HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ " In the beginning, we are having some import statements that are actually providing us with the required modules and libraries\n",
+ "for proper execution of our code.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of retrieving bios settings from iLO servers.\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the get_bios_settings function, after everything is done this function will give details about bios settings of system.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
get_bios_setting function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In case the resource directory was disabled we are using systems making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings.
- For that purpose simply we are making series of get requests.
\n",
+ " We make a final get operation by at the location bios_uri and save the response inside bios_data.\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately, if bios_data variable is not null we print out information about bios settings. \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_bios_setting(_redfishobj):\n",
+ "\n",
+ " bios_uri = None\n",
+ " bios_data = None\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " break\n",
+ "\n",
+ " if bios_data:\n",
+ " print(\"\\n\\nShowing bios attributes before changes:\\n\\n\")\n",
+ " print(json.dumps(bios_data.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to get_bios_settings function to obtain information about bios settings of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdin",
+ "output_type": "stream",
+ "text": [
+ "Enter iLO IP address: 15.146.51.201\n",
+ "Enter Username: Administrator\n",
+ "Enter password: 12iso*help\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Initializing no proxy.\n",
+ "Redirecting 15.146.51.201/redfish/v1/ -> https://15.146.51.201/redfish/v1/\n",
+ "Response Time to /redfish/v1/: 0.4612421989440918 seconds.\n",
+ "Performing session authentication.\n",
+ "Redirecting 15.146.51.201/redfish/v1/SessionService/Sessions/ -> https://15.146.51.201/redfish/v1/SessionService/Sessions/\n",
+ "Response Time to /redfish/v1/SessionService/Sessions/: 0.23828959465026855 seconds.\n",
+ "{'@odata.context': '/redfish/v1/$metadata#Session.Session', '@odata.etag': 'W/\"B18A5BAF\"', '@odata.id': '/redfish/v1/SessionService/Sessions/administrator0000000062d211f0f2b02038/', '@odata.type': '#Session.v1_0_0.Session', 'Id': 'administrator0000000062d211f0f2b02038', 'Description': 'Manager User Session', 'Name': 'User Session', 'Oem': {'Hpe': {'@odata.context': '/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession', '@odata.type': '#HpeiLOSession.v2_1_0.HpeiLOSession', 'AccessTime': '2022-07-16T01:18:40Z', 'LoginTime': '2022-07-16T01:18:40Z', 'MySession': False, 'UserExpires': '2022-07-16T01:48:40Z', 'UserIP': '16.242.171.23', 'UserTag': 'REST', 'UserType': 'Local'}}, 'UserName': 'Administrator'}\n",
+ "Login returned code 201: {\"@odata.context\":\"/redfish/v1/$metadata#Session.Session\",\"@odata.etag\":\"W/\\\"B18A5BAF\\\"\",\"@odata.id\":\"/redfish/v1/SessionService/Sessions/administrator0000000062d211f0f2b02038/\",\"@odata.type\":\"#Session.v1_0_0.Session\",\"Id\":\"administrator0000000062d211f0f2b02038\",\"Description\":\"Manager User Session\",\"Name\":\"User Session\",\"Oem\":{\"Hpe\":{\"@odata.context\":\"/redfish/v1/$metadata#HpeiLOSession.HpeiLOSession\",\"@odata.type\":\"#HpeiLOSession.v2_1_0.HpeiLOSession\",\"AccessTime\":\"2022-07-16T01:18:40Z\",\"LoginTime\":\"2022-07-16T01:18:40Z\",\"MySession\":false,\"UserExpires\":\"2022-07-16T01:48:40Z\",\"UserIP\":\"16.242.171.23\",\"UserTag\":\"REST\",\"UserType\":\"Local\"}},\"UserName\":\"Administrator\"}\n"
+ ]
+ },
+ {
+ "ename": "AttributeError",
+ "evalue": "'RedfishClient' object has no attribute 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_32988/1002653862.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 19\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 20\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m \u001b[0mget_bios_setting\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 22\u001b[0m \u001b[0mREDFISHOBJ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlogout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_32988/1804850166.py\u001b[0m in \u001b[0;36mget_bios_setting\u001b[1;34m(_redfishobj)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mbios_uri\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mbios_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mresource_instances\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_redfishobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_resource_directory\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_redfishobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mDISABLE_RESOURCE_DIR\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mresource_instances\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;31m#if we do not have a resource directory or want to force it's non use to find the\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mAttributeError\u001b[0m: 'RedfishClient' object has no attribute 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_bios_setting(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/get_powermetrics_average.ipynb b/examples/Jupyter_notebooks/examples/get_powermetrics_average.ipynb
new file mode 100644
index 0000000..81c02f5
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/get_powermetrics_average.ipynb
@@ -0,0 +1,226 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# GETTING POWERMETRICS AVERAGE"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
get powermetrics average about HPE iLO system. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code.
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ModuleNotFoundError",
+ "evalue": "No module named 'get_resource_directory'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_15656/4041776832.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mredfish\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mServerDownOrUnreachableError\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mget_resource_directory\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mget_resource_directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'get_resource_directory'"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "An example of gathering the power metrics average on HPE iLO systems\n",
+ "\"\"\"\n",
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "from get_resource_directory import get_resource_directory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This is our powermetrics function overview, in the end this will give us with power related information.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. In the
get_powermetrics_average function we are first using
resource_instances variable to obtain information about the resource directory by using get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2. In the ILO rest api the information about power metrics is stored inside the
chassis json object.\n",
+ " Through chassis_response variable we are making a http
GET operation to and trying to obtain the power metrics about iLO system.\n",
+ "
\n",
+ "\n",
+ "3. In the chassis response object we are iterating on all the members with different
odata_id .\n",
+ " Then again an http GET request is made and response is stored in
chassis_members_response.\n",
+ " The power metrics information is ultimately present in the
chassis_members_response.\n",
+ "
\n",
+ "\n",
+ "4. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if power attribute is present in
@odata.type attribute then we'll store information about power metrics in power_metrics_uri and break out of iteration.\n",
+ "
\n",
+ "\n",
+ "Ultimately if power_metrics_uri was obtained without any errors then get the information at the relevant uri and print out that information .\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " - Once your credentials that are enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - If not then we make a call to get_powermetrics_average function to obtain power related info of system.
\n",
+ " - After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = \"https://10.0.0.100\"\n",
+ " LOGIN_ACCOUNT = \"admin\"\n",
+ " LOGIN_PASSWORD = \"password\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/modify_user_account.ipynb b/examples/Jupyter_notebooks/examples/modify_user_account.ipynb
new file mode 100644
index 0000000..9742aca
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/modify_user_account.ipynb
@@ -0,0 +1,317 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Modify the user account"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
modify_user_account!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This is our modify_ilo_user_account function overview, in the end this will give us about modifying the ilo user account related information.
\n",
+ "
Let me give you a walk through of it!
\n",
+ "
\n",
+ " - Users are having a facility to modify their ilo accounts. They can change their username, password and role using the below function.
\n",
+ " - If we don't have a resource directory, information about the account is stored inside the account_service json object. Through account_service_response variable we are making a http GET operation to and trying to obtain the account details of an user in iLO system.
\n",
+ " - account_collection_uri gives the response for that member about the user information
\n",
+ " - If the resource directory is present, then we will simply iterate through all instances inside resources and if the account_collection_uri is present in @odata.type attribute then we will store information in a dictionary called body which recieves the values like new_username, new_password and is updated.
\n",
+ " - If a non-existing user tries to change the account, then it throws error.
\n",
+ " - Finally, the username and password is updated.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def modify_ilo_user_account(_redfishobj, username_to_modify, new_loginname, new_username, \\\n",
+ " new_password, role_id, privilege_dict):\n",
+ "\n",
+ " account_collection_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ "\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #resource directory is not available so we will navigate through paths manually to obtain\n",
+ " #account info\n",
+ " account_service_uri = _redfishobj.root.obj['AccountService']['@odata.id']\n",
+ " account_service_response = _redfishobj.get(account_service_uri)\n",
+ " account_collection_uri = account_service_response.obj['Accounts']['@odata.id']\n",
+ " #modify role id\n",
+ " if role_id:\n",
+ " body = {\"RoleId\": role_id}\n",
+ " else:\n",
+ " #obtain all account instances from resource directory\n",
+ " for instance in resource_instances:\n",
+ " if '#ManagerAccountCollection.' in instance['@odata.type']:\n",
+ " account_collection_uri = instance['@odata.id']\n",
+ " if privilege_dict:\n",
+ " #HPE server, so modify privileges\n",
+ " body = {\"Oem\": {\"Hpe\": {\"Privileges\": {}}}}\n",
+ " for priv in privilege_dict:\n",
+ " body[\"Oem\"][\"Hpe\"][\"Privileges\"][priv] = privilege_dict[priv]\n",
+ " if new_loginname:\n",
+ " #modify login name\n",
+ " body[\"Oem\"][\"Hpe\"][\"LoginName\"] = new_loginname\n",
+ "\n",
+ " if new_username:\n",
+ " body[\"UserName\"] = new_username\n",
+ " if new_password:\n",
+ " body[\"Password\"] = new_password\n",
+ "\n",
+ " #find the account to modify\n",
+ " account_uri_to_modify = None\n",
+ " account_uris = REDFISHOBJ.get(account_collection_uri)\n",
+ " for account_uri in account_uris.dict['Members']:\n",
+ " account = REDFISHOBJ.get(account_uri['@odata.id'])\n",
+ " if account.dict['UserName'] == username_to_modify:\n",
+ " account_uri_to_modify = account_uri['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if not account_uri_to_modify:\n",
+ " sys.stderr.write(\"Cannot find account to modify\")\n",
+ " return\n",
+ "\n",
+ " #modify the account\n",
+ " resp = REDFISHOBJ.patch(account_uri_to_modify, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of '%s' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get \"server not reachable\" message!
\n",
+ " - and Once everything is done you are automatically logged out with .logout() 😁.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #username of the account to modify\n",
+ " USERNAME_TO_MODIFY = input(\"Enter the username to be modified: \")\n",
+ " # USERNAME_TO_MODIFY = \"bruce_wayne\"\n",
+ "\n",
+ " #account login name to change the account to\n",
+ " NEW_LOGINNAME = input(\"Enter the new login name: \")\n",
+ " # NEW_LOGINNAME = \"joker\"\n",
+ "\n",
+ " #account user name to change the account to\n",
+ " NEW_USERNAME = input(\"Enter the new username: \")\n",
+ " # NEW_USERNAME = \"joker\"\n",
+ "\n",
+ " #account password to change the account to\n",
+ " NEW_PASSWORD = getpass.getpass(\"Enter the new password: \")\n",
+ " # NEW_PASSWORD = \"joker123\"\n",
+ "\n",
+ " #role to change account to\n",
+ " ROLE_ID = input(\"Enter the Role ID: (Administrator, ReadOnly or Operator are available)\")\n",
+ " # ROLE_ID = \"ReadOnly\"\n",
+ "\n",
+ " #update HPE account privileges\n",
+ " PRIVILEGE_DICT = {\"iLOConfigPriv\": False, \"VirtualMediaPriv\": False, \"RemoteConsolePriv\": True,\\\n",
+ " \"UserConfigPriv\": False, \"VirtualPowerAndResetPriv\": False, \\\n",
+ " \"SystemRecoveryConfigPriv\": False, \"LoginPriv\": True, \\\n",
+ " \"HostStorageConfigPriv\": False, \"HostNICConfigPriv\": False, \\\n",
+ " \"HostBIOSConfigPriv\": False}\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " modify_ilo_user_account(REDFISHOBJ, USERNAME_TO_MODIFY, NEW_LOGINNAME, NEW_USERNAME, \\\n",
+ " NEW_PASSWORD, ROLE_ID, PRIVILEGE_DICT)\n",
+ "\n",
+ " REDFISHOBJ.logout()\n",
+ "\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " find_ilo_mac_address(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/reboot_server (1).ipynb b/examples/Jupyter_notebooks/examples/reboot_server (1).ipynb
new file mode 100644
index 0000000..2d90a23
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/reboot_server (1).ipynb
@@ -0,0 +1,234 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# REBOOTING A SERVER"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello User.!
Welcome to
python-iLOrest-library This is the example to
perform rebooting of a server. As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "
1
\n",
+ "In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ "for proper execution of our code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2
\n",
+ "In below cell is the reboot_server function.\n",
+ "Current cell is the overview of it, utimately at the end this will reboot the server and provide the response for the same.\n",
+ "
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to obtain the power metrics information.\n",
+ "\n",
+ "1. In the
reboot server function we are first using
system_members_response variable to obtain information about the path at which server related information is stored by using couple of get requests.\n",
+ "
\n",
+ "2. If the resource directory was accessible then we simply search for
'#ComputerSystem' key (as this is the place comprising of server related information inside the
instance['odata.type'] dictionary and finally making a get request to that location.\n",
+ "
\n",
+ " \n",
+ "3. If we obtain systems_response successfully then a
ressettype list is created specifying the parameters that how we want to restart.\n",
+ " \n",
+ "\n",
+ "4. Later both the parameters are passed into a new dictionary named body and post request is created to make changes on the server side.\n",
+ " A successful
HTTP post request will set the values at server end so that a server gets rebooted.\n",
+ " \n",
+ "\n",
+ "5. Lastly, we also save response status inside
resp variable and check what is the status code returned to confirm whether the post request was success or not. If success then response by server is printed and if not then error message is printed.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reboot_server(_redfishobj):\n",
+ "\n",
+ " systems_members_response = None\n",
+ "\n",
+ " resource_instances = get_resource_directory(_redfishobj.get_resource_directory)\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#ComputerSystem.' in instance['@odata.type']:\n",
+ " systems_uri = instance['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ "\n",
+ " if systems_response:\n",
+ " system_reboot_uri = systems_response.obj['Actions']['#ComputerSystem.Reset']['target']\n",
+ " body = dict()\n",
+ " resettype = ['ForceRestart','GracefulRestart']\n",
+ " body['Action'] = 'ComputerSystem.Reset'\n",
+ " for reset in resettype:\n",
+ " if reset.lower() == \"forcerestart\":\n",
+ " body['ResetType'] = \"ForceRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ " elif reset.lower() == \"gracefulrestart\":\n",
+ " body['ResetType'] = \"GracefulRestart\"\n",
+ " resp = _redfishobj.post(system_reboot_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE TO PROCEED FURTHER
\n",
+ "
\n",
+ " \n",
+ "- Once your credentials that are enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server.
\n",
+ "- If server is down or Unreachable we get server not reachable message!
\n",
+ "- If not then we make a call to reboot_server function to perform rebooting of server.
\n",
+ "- After getting required information Redfish.logout()closses the particular session and logs us out of the system.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reboot_server(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally use the following commented values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ "\n",
+ " When running remotely connect using the secured (https://) address,\n",
+ " account name, and password to send https requests\n",
+ "
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " https://10.0.0.100
\n",
+ " https://ilo.hostname\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Jupyter_notebooks/examples/reset_ilo.ipynb b/examples/Jupyter_notebooks/examples/reset_ilo.ipynb
new file mode 100644
index 0000000..999bc97
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/reset_ilo.ipynb
@@ -0,0 +1,252 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7d4d890e",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Resetting iLO manager"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "62aaa233",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
reset the ilo manager!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fbfec992",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "9b53ecf2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b8c9efd9",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "\n",
+ "
2.
Below is the overview of reset_ilo function. In this function we are resetting values for an iLO manager.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. In the
function we are first using
resource_instances variable to obtain information about the resource directory by using
get_resource_directory module.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "2. If the resource directory is enabled or we want to force it's non-use then navigate to the directory where managers members data is present. We make two http get requests to obtain the directory where we actually need to perform the reset operation.\n",
+ "
manager_member_response saves the result of final http get request made in this case.\n",
+ "
\n",
+ "\n",
+ "3. Else if resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if
#\"Manager\" attribute is present inside the record
instances[@odata.type]. we save the uri inside of manager_member_response. \n",
+ "
\n",
+ "4.
\n",
+ " - Lastly, we navigate in the manager_member_response by following this path 'Actions'->'#Manager.Reset'->'target'to obtained the url at which reset opreation has to be made and save the same inside reset_ilo_uri.
- On the next line we create a dictionary having the value of 'Action' as 'Manager.Reset' and make a POST request to server and pass the same dictionary so as to make changes at the reset_ilo_url location.
\n",
+ "
\n",
+ " \n",
+ " If the response of this POST request was 400 it means there was some error from server-side while doing the same operation.
\n",
+ " Else there can also be an error which we aren't aware of, in that case we print out the response status code alongwith erro message .
\n",
+ " Ultimately, if everything went properly we print out the response object along with success message.\n",
+ " \n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "93003c6b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def reset_ilo(_redfishobj, DISABLE_RESOURCE_DIR):\n",
+ "\n",
+ " managers_members_response = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Manager.' in instance['@odata.type']:\n",
+ " managers_members_uri = instance['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ "\n",
+ " if managers_members_response:\n",
+ " reset_ilo_uri = managers_members_response.obj['Actions']['#Manager.Reset']['target']\n",
+ " body = {'Action': 'Manager.Reset'}\n",
+ " resp = _redfishobj.post(reset_ilo_uri, body)\n",
+ "\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended Message \"\\\n",
+ " \"Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5a583e0e",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
This is Main function overview.
\n",
+ " Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to change the settings.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient object is being created mainly to log into the system with valid credentials.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "3. We try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "4. Then we call reset_ilofunction with our redfish object and the function does the resetting of manager.
\n",
+ " \n",
+ "\n",
+ "5. Lastly, REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "85745d7d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = True\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " reset_ilo(REDFISHOBJ, DISABLE_RESOURCE_DIR)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "69132144",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ea6fce6f",
+ "metadata": {},
+ "source": [
+ "In case you need help 🔗 links to relevant resources :\n",
+ "
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ " \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/set_bios_password.ipynb b/examples/Jupyter_notebooks/examples/set_bios_password.ipynb
new file mode 100644
index 0000000..dae0399
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/set_bios_password.ipynb
@@ -0,0 +1,236 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "d357d38b",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Setting Bios Password"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fce7e904",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
change bios password for HPE iLO system!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ " Also do run each succesive cell of code \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a89aa82f",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "
\n",
+ "
In the beginning, we are having some import statements that are actually providing us with the required modules and libraries.\n",
+ " for proper execution of our code.
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e96dc046",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "828be423",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2.
\n",
+ " Below is the set_bios_password function, through which we can change the password of bios system.
\n",
+ "
Let me give you a walk through of it!\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api and everything is in form of
JSON objects i.e. name-value pairs. So we are simply following the hierarchy to navigate to required information.\n",
+ "\n",
+ "1. In the
set_bios_setting function we are taking three parameters i.e.
Redfish object,
new_password and exisiting password as
bios_password. Also
resource_instances variable is being obtain information about the resource directory by using
get_resource_directory module.\n",
+ "
\n",
+ " \n",
+ "2.
If the resource directory was disabled we are making a series of http
GET. requests to the server so as to obtain info about bios settings.\n",
+ "
\n",
+ " - The information about bios settings is present inside a particular json object of iLO rest api.
- We just need to navigate to that directory so as to obtain info about bios settings and later make changes to the existing password.
- For that purpose simply we are making series of get requests.
\n",
+ " - After navigating through iLO rest api we actually save the http address of location where bios settings are present inside bios_uri
\n",
+ "
\n",
+ "
\n",
+ " \n",
+ "\n",
+ "3.
Else if the resource directory is enabled then we will simply iterate through all instances inside resources \n",
+ " and if #bios attribute is present in
@odata.type attribute then we'll store information about bios settings of the system inside of bios_data variable and break out of iteration.\n",
+ "
\n",
+ "4.
If bios_uri is not null after making above operations, we can perform the required actions to change the bios password.
\n",
+ " - Following up we make get request and obtain the URL of the location where we are actually going to make the changes.
- Ultimately, we make a post request by passing the bios_change_pass_uri and body dictionary that contains the changes made to the password.
\n",
+ " - The job of post request here is to update the password at the provided location and send a response whether the job was done properly or not.
\n",
+ " \n",
+ " If the reponse status code was anything other than 200 or 201 then we can print out the response status code and error message.
\n",
+ " Else we print out success message with the response obtained after making post request.\n",
+ "
\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "ee515d74",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def set_bios_password(_redfishobj, new_password, bios_password):\n",
+ "\n",
+ " bios_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " systems_uri = _redfishobj.root.obj['Systems']['@odata.id']\n",
+ " systems_response = _redfishobj.get(systems_uri)\n",
+ " systems_members_uri = next(iter(systems_response.obj['Members']))['@odata.id']\n",
+ " systems_members_response = _redfishobj.get(systems_members_uri)\n",
+ " bios_uri = systems_members_response.obj['Bios']['@odata.id']\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#Bios.' in instance['@odata.type']:\n",
+ " bios_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if bios_uri:\n",
+ " bios_data = _redfishobj.get(bios_uri)\n",
+ " bios_change_pass_uri = bios_data.obj['Actions']['#Bios.ChangePassword']['target']\n",
+ " body = dict()\n",
+ " body[\"PasswordName\"] = \"Administrator\"\n",
+ " body[\"OldPassword\"] = bios_password\n",
+ " body[\"NewPassword\"] = new_password\n",
+ " resp = _redfishobj.post(bios_change_pass_uri, body)\n",
+ " #If iLO responds with soemthing outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b93c0d7",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
\n",
+ "
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish object is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - We are passing the required information to change the password of iLO user account i.e. base_url, username, password
\n",
+ " - If server is down or Unreachable we get server not reachable message!
\n",
+ " - Once everything is done you are automatically logged out.
\n",
+ " - Need more help . Please check here\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "38b9fd3a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " SYSTEM_URL = input(\"Enter System URL: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Name: \")\n",
+ " LOGIN_PASSWORD = input(\"Enter password: \")\n",
+ "\n",
+ " #new BIOS password\n",
+ " NEW_BIOS_PASSWORD = \"password\"\n",
+ " #old BIOS password\n",
+ " OLD_BIOS_PASSWORD = \"password\"\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " set_bios_password(REDFISHOBJ, NEW_BIOS_PASSWORD, OLD_BIOS_PASSWORD)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "34f69788",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/examples/test_ESKM_connection.ipynb b/examples/Jupyter_notebooks/examples/test_ESKM_connection.ipynb
new file mode 100644
index 0000000..0ff9077
--- /dev/null
+++ b/examples/Jupyter_notebooks/examples/test_ESKM_connection.ipynb
@@ -0,0 +1,239 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3dfca749-3331-47de-9d47-c705fdbfd813",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# Testing ESKM Connection"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac00ccdd-3ac6-49f0-87eb-4f9c9dc185a2",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
Hello there.!
Welcome to
python-iLOrest-library Here is an example to
test_ESKM_connection!!! As you are here let's get it done easily.
\n",
+ " To perform this u need to have
python-ilorest-library installed in your machine.
\n",
+ " And please keep your username and password handy!\n",
+ "
\n",
+ "
Also do execute each successive cell once to avoid any errors!\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a347c8c-d1fb-4ccf-94aa-73d7d0f42199",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1.
\n",
+ "Below we are importing all the necessary modules from the ilorest library!.
\n",
+ "
sys \n",
+ " \n",
+ "
json \n",
+ "
redfish \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7873d333-4738-4dfc-8cf3-8e424eafaa48",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "import getpass\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d83f828e-a91e-4efc-b70f-e14a01b3cd44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
This is our test_ESKM_connection function overview, in the end this will give us about the ESKM connection related information.
\n",
+ "
Let me give you a walk through of it!
\n",
+ "
\n",
+ " - Enterprise Secure Key Manager(ESKM) is used by HPE to protect customer and user data. To check the connection of eskm, test_ESKM_connection function is used.
\n",
+ " - If we don't have a resource directory, information about the security service is stored inside the managers json object. Through managers_response variable we are making a http GET operation to and trying to obtain the security_service_uri in the iLO system.
\n",
+ " - eskm_uri stores the value of the security_service_uri
\n",
+ " - If the resource directory is present, then we will simply iterate through all instances inside resources and if the ESKM instance is present in @odata.type attribute then we will store information in eskm_uri and break out of iteration.
\n",
+ " - Finally, we check fot the eskm_uri and a http response is created indicating the successfull retrival of information.
\n",
+ " - More details can be found out using this Link\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e307a7c-e9e0-4033-a9be-374e7ade9e0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def test_ESKM_connection(_redfishobj):\n",
+ "\n",
+ " eskm_uri = None\n",
+ " body = dict()\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " managers_uri = _redfishobj.root.obj['Managers']['@odata.id']\n",
+ " managers_response = _redfishobj.get(managers_uri)\n",
+ " managers_members_uri = next(iter(managers_response.obj['Members']))['@odata.id']\n",
+ " managers_members_response = _redfishobj.get(managers_members_uri)\n",
+ " security_service_uri = managers_members_response.obj.Oem.Hpe.Links['SecurityService']\\\n",
+ " ['@odata.id']\n",
+ " security_service_response = _redfishobj.get(security_service_uri)\n",
+ " eskm_uri = security_service_response.obj.Links['ESKM']['@odata.id']\n",
+ "\n",
+ " else:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " for instance in resource_instances:\n",
+ " if '#HpeESKM.' in instance['@odata.type']:\n",
+ " eskm_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if eskm_uri:\n",
+ " eskm_test_conn_uri = _redfishobj.get(eskm_uri).obj['Actions']\\\n",
+ " ['#HpeESKM.TestESKMConnections']['target']\n",
+ " body[\"Action\"] = \"HpeESKM.TestESKMConnections\"\n",
+ " resp = _redfishobj.post(eskm_test_conn_uri, body)\n",
+ " #If iLO responds with something outside of 200 or 201 then lets check the iLO extended info\n",
+ " #error message to see what went wrong\n",
+ " if resp.status == 400:\n",
+ " try:\n",
+ " print(json.dumps(resp.obj['error']['@Message.ExtendedInfo'], indent=4, \\\n",
+ " sort_keys=True))\n",
+ " except Exception as excp:\n",
+ " sys.stderr.write(\"A response error occurred, unable to access iLO Extended \"\\\n",
+ " \"Message Info...\")\n",
+ " elif resp.status != 200:\n",
+ " sys.stderr.write(\"An http response of \\'%s\\' was returned.\\n\" % resp.status)\n",
+ " else:\n",
+ " print(\"Success!\\n\")\n",
+ " print(json.dumps(resp.dict, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d4e940e6-887e-4e35-8f77-bc331ade4485",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3.
The Main function: PLEASE ENTER YOU LOGIN CREDENTIALS HERE.
\n",
+ "
\n",
+ " - Once you enter everything a redfish obejct is created with the help of RedfishClient class and a session is created and now you will be logged in to the server
\n",
+ " - If server is down or Unreachable we get \"server not reachable\" message!
\n",
+ " - and Once everything is done you are automatically logged out with .logout() 😁.
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6398fb6f-5672-4075-bf73-8af549f172de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " # When running on the server locally use the following commented values\n",
+ " #SYSTEM_URL = None\n",
+ " #LOGIN_ACCOUNT = None\n",
+ " #LOGIN_PASSWORD = None\n",
+ "\n",
+ " # When running remotely connect using the secured (https://) address,\n",
+ " # account name, and password to send https requests\n",
+ " # SYSTEM_URL acceptable examples:\n",
+ " # \"https://10.0.0.100\"\n",
+ " # \"https://ilo.hostname\"\n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, \\\n",
+ " password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " test_ESKM_connection(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "615ad0b4-156f-478d-b6cb-8a12ad7117c3",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally : use the following values
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address,account name, and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bd8051b-cc81-4dca-8b8f-c86202b35880",
+ "metadata": {},
+ "source": [
+ "\n",
+ " In case you need help 🔗 links to relevant resources :
\n",
+ " 1.Python-ilorest-library:
LINK\n",
+ " 2.Hpe ilorest-api explorer:
LINK\n",
+ " 3.Rest api:
LINK\n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Jupyter_notebooks/index.ipynb b/examples/Jupyter_notebooks/index.ipynb
new file mode 100644
index 0000000..58031df
--- /dev/null
+++ b/examples/Jupyter_notebooks/index.ipynb
@@ -0,0 +1,53 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "453f77bb-9a66-492a-bf03-a737b524a484",
+ "metadata": {},
+ "source": [
+ "|OPERATION|DESCRIPTION| METHOD | LOCATION |\n",
+ "|-------------|--------------------------------------|-------------------------|------------------------|\n",
+ "|bios settings|update bios settings for iLO server| PATCH |[change_bios_setting](examples/change_bios_settings.ipynb)|\n",
+ "|bios default| update bios to default setting | PATCH |[revert_bios_default](examples/bios_revert_default.ipynb)|\n",
+ "|powermetrics average|get powewr measurement average of servers| GET |[get_powermetrics_average](examples/get_powermetrics_average.ipynb)|\n",
+ "|change boot order|update the existing boot order or add new order| PUT |[change_boot_order](examples/change_bios_settings.ipynb)|\n",
+ "|change temporary boot order|update or reset an temporary boot order| PUT |[change_temporary_boot_order](examples/change_bios_settings.ipynb)|\n",
+ "|clear ahs data | clear active health state data of iLO server| DELETE |[clear_ahs_data](examples/clear_ahs_data.ipynb)|\n",
+ "|computer details|get all the available computer/hosts details in iLO| GET |[computer_details](examples/computer_details.ipynb)|\n",
+ "|expand data|expand the response data obtained from any of the http methods| GET |[expand_data](examples/change_bios_settings.ipynb)\n",
+ "|generate_csr|obtain a certificate signing request for iLO server | GET |[generate_csr](examples/generate_csr.ipynb)|\n",
+ "|get ahs info|obtain active health status data of the iLO servers| GET |[get_ahs_data](examples/get_ahs_data.ipynb)|\n",
+ "|base message registry|get base message registry info of iLO servers| GET |[get_base_registry](examples/change_bios_settings.ipynb)|\n",
+ "|iLO ip address|obtain the ip address of iLO servers| GET |[get_ilo_ip](examples/get_ilo_ip.ipynb)|\n",
+ "|License key|get iLO license key for iLO| GET |[get_license_key](examples/get_license_key.ipynb)|\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "974fdedd-2bb1-4a4c-adb5-a6052e134085",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/ilo5.zip b/examples/ilo5.zip
new file mode 100644
index 0000000..7755775
Binary files /dev/null and b/examples/ilo5.zip differ
diff --git a/python-ilorest-library b/python-ilorest-library
new file mode 160000
index 0000000..97888a5
--- /dev/null
+++ b/python-ilorest-library
@@ -0,0 +1 @@
+Subproject commit 97888a5fcadd0fee338caedda287bb7c6c804a32
diff --git a/src/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb b/src/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb
new file mode 100644
index 0000000..8c21f3f
--- /dev/null
+++ b/src/.ipynb_checkpoints/Get_Powermetrics_Average-checkpoint.ipynb
@@ -0,0 +1,256 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/src/Expand_data.ipynb b/src/Expand_data.ipynb
new file mode 100644
index 0000000..6d38569
--- /dev/null
+++ b/src/Expand_data.ipynb
@@ -0,0 +1,233 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b6480262",
+ "metadata": {},
+ "source": [
+ "Example of expanding data responses
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "051ce734",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "58eab40d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cfa6671a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5f4583b",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our expand_data function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The expand_data function takes two parameters: _redfishobj and expand_url, with a default value of \"/redfish/v1/\" for expand_url.
\n",
+ " \n",
+ "2. It sends a GET request to the _redfishobj (Redfish object) using the provided expand_url to retrieve the response.
\n",
+ "\n",
+ "3. Another GET request is sent to the _redfishobj with the expand_url appended with ?$expand=.. This request is used to retrieve an expanded response.
\n",
+ "\n",
+ "4. The function then prints the standard response to the standard output stream.
\n",
+ "\n",
+ "5. The standard response, represented as a dictionary, is printed.
\n",
+ "\n",
+ "6. Next, the function prints the expanded response to the standard output stream.
\n",
+ " \n",
+ "7. The expanded response, represented as a dictionary, is printed.
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "509e8725",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def expand_data(_redfishobj, expand_url=\"/redfish/v1/\"):\n",
+ "\n",
+ " response = _redfishobj.get(expand_url)\n",
+ " exp_response = _redfishobj.get(expand_url+'?$expand=.')\n",
+ " sys.stdout.write('Standard response:\\n')\n",
+ " sys.stdout.write('\\t'+str(response.dict)+'\\n')\n",
+ " sys.stdout.write('Expanded response:\\n')\n",
+ " sys.stdout.write('\\t'+str(exp_response.dict)+'\\n')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "523f5bda",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ " \n",
+ "5. When prompted for URL, enter the URL that you want to be expanded. Example: /redfish/v1/systems/
\n",
+ " \n",
+ "6. Then we call expand_data with our redfish object and EXPAND_URL.
\n",
+ " \n",
+ "\n",
+ "7. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b80bdfed",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "eabae678",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Enter iLO IP address: hye\n",
+ "Enter Username: ue\n"
+ ]
+ }
+ ],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " #url to be expanded\n",
+ " EXPAND_URL = input(\"Enter the URL that is to be expanded (Ex: /redfish/v1/systems/)\")\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " expand_data(REDFISHOBJ, EXPAND_URL)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "76b99be7",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6d2bbf56",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/src/Get_Powermetrics_Average.ipynb b/src/Get_Powermetrics_Average.ipynb
new file mode 100644
index 0000000..8c21f3f
--- /dev/null
+++ b/src/Get_Powermetrics_Average.ipynb
@@ -0,0 +1,256 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "029d388f",
+ "metadata": {},
+ "source": [
+ "Gathering the power metrics average on HPE iLO systems
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e04b1c54",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41203a2d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
1. Below we are importing all the necessary python libraries
\n",
+ "
\n",
+ " - sys
\n",
+ " - json
\n",
+ " - redfish
\n",
+ " - getpass - to take password as inputs securely
\n",
+ "
\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dc837b94",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import json\n",
+ "from redfish import RedfishClient\n",
+ "from redfish.rest.v1 import ServerDownOrUnreachableError\n",
+ "\n",
+ "#from get_resource_directory import get_resource_directory\n",
+ "\n",
+ "import getpass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db36318d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
2. This is our get_powermetrics_average function overview.
\n",
+ " \n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to do this.
\n",
+ "\n",
+ "1. The function get_powermetrics_average takes _redfishobj as a parameter, which represents the Redfish object used to interact with the server.\n",
+ "
\n",
+ " \n",
+ "2. It initializes the variable power_metrics_uri to None.\n",
+ "
\n",
+ "\n",
+ "3. The function attempts to retrieve the resource directory using the _redfishobj.get_resource_directory() method. If the resource directory is disabled or not available, it follows an alternative approach to find the relevant URI.\n",
+ "
\n",
+ "\n",
+ "4. If the resource directory is disabled or not available, it retrieves the chassis URI from the root object using _redfishobj.root.obj['Chassis']['@odata.id'] and makes a GET request to obtain the chassis response.\n",
+ "
\n",
+ "\n",
+ "5. Within the chassis members response, it retrieves the URI for power metrics under the HPE OEM namespace using chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']. This URI represents the power metrics data.\n",
+ "
\n",
+ "\n",
+ "6. If the resource directory is available, the function iterates through the resource instances obtained from the resource directory.\n",
+ "
\n",
+ " \n",
+ "7. It checks if the @odata.type of the instance contains '#Power.', indicating that it represents power metrics. If found, it sets the power_metrics_uri variable to the @odata.id of the instance and breaks the loop.\n",
+ "
\n",
+ " \n",
+ "8. If the power_metrics_uri is not None, it makes a GET request to retrieve the power metrics data using _redfishobj.get(power_metrics_uri).obj.Oem.Hpe.\n",
+ "
\n",
+ " \n",
+ " \n",
+ "9. The function then prints the power data, represented as a JSON object.\n",
+ "
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b5104a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_powermetrics_average(_redfishobj):\n",
+ "\n",
+ " power_metrics_uri = None\n",
+ "\n",
+ " resource_instances = _redfishobj.get_resource_directory()\n",
+ " if DISABLE_RESOURCE_DIR or not resource_instances:\n",
+ " #if we do not have a resource directory or want to force it's non use to find the\n",
+ " #relevant URI\n",
+ " chassis_uri = _redfishobj.root.obj['Chassis']['@odata.id']\n",
+ " chassis_response = _redfishobj.get(chassis_uri)\n",
+ " chassis_members_uri = next(iter(chassis_response.obj['Members']))['@odata.id']\n",
+ " chassis_members_response = _redfishobj.get(chassis_members_uri)\n",
+ " power_metrics_uri = chassis_members_response.obj.Oem.Hpe['Power']['@odata.id']\n",
+ " else:\n",
+ " for instance in resource_instances:\n",
+ " #Use Resource directory to find the relevant URI\n",
+ " if '#Power.' in instance['@odata.type']:\n",
+ " power_metrics_uri = instance['@odata.id']\n",
+ " break\n",
+ "\n",
+ " if power_metrics_uri:\n",
+ " power_metrics_data = _redfishobj.get(power_metrics_uri).obj.Oem.Hpe\n",
+ " print(\"\\n\\nPower Data:\\n\\n\")\n",
+ " print(json.dumps(power_metrics_data, indent=4, sort_keys=True))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d38fc2fb",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
3. This is Main function overview.
\n",
+ "
\n",
+ " There is a hierarchy involved in iLO Rest Api. So we are simply following the hierarchy present to get the power metrics average.\n",
+ "\n",
+ "1. The rest opertions are handled by redfish object which is created by RedfishClient
\n",
+ "
\n",
+ " \n",
+ "2. RedfishClient class takes 3 parameters iLO url, Username, Password and returns a redfish object.
\n",
+ "
\n",
+ "\n",
+ "3. Once you enter everything a redfish obejct is created with the help of RedfishClient class.
\n",
+ "
\n",
+ "\n",
+ "4. Now we try to Login with the help of REDFISHOBJ, if it is successful a session is created and you are logged in, But if Server is not avaialbe we get an error saying \"server unreachable\"
\n",
+ "
\n",
+ "5. Then we call get_powermetrics_average with our redfish object.
\n",
+ " \n",
+ "\n",
+ "6. REDFISHOBJ.logout() will take care of logging you out of the ilo.\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d2be84",
+ "metadata": {},
+ "source": [
+ "\n",
+ " When running on the server locally,use the following values:
\n",
+ " SYSTEM_URL = None
\n",
+ " LOGIN_ACCOUNT = None
\n",
+ " LOGIN_PASSWORD = None
\n",
+ " When running remotely connect using the secured (https://) address, account name and password to send https requests
\n",
+ " SYSTEM_URL acceptable examples:
\n",
+ " \"https://10.0.0.100\"
\n",
+ " \"https://ilo.hostname\"\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1399a2d5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if __name__ == \"__main__\":\n",
+ " \n",
+ " SYSTEM_URL = input(\"Enter iLO IP address: \")\n",
+ " LOGIN_ACCOUNT = input(\"Enter Username: \")\n",
+ " LOGIN_PASSWORD = getpass.getpass(\"Enter password: \")\n",
+ "\n",
+ " # flag to force disable resource directory. Resource directory and associated operations are\n",
+ " # intended for HPE servers.\n",
+ " DISABLE_RESOURCE_DIR = False\n",
+ "\n",
+ " try:\n",
+ " # Create a Redfish client object\n",
+ " REDFISHOBJ = RedfishClient(base_url=SYSTEM_URL, username=LOGIN_ACCOUNT, password=LOGIN_PASSWORD)\n",
+ " # Login with the Redfish client\n",
+ " REDFISHOBJ.login()\n",
+ " except ServerDownOrUnreachableError as excp:\n",
+ " sys.stderr.write(\"ERROR: server not reachable or does not support RedFish.\\n\")\n",
+ " sys.exit()\n",
+ "\n",
+ " get_powermetrics_average(REDFISHOBJ)\n",
+ " REDFISHOBJ.logout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dcb75619",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "045e852d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}