summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-03-15 16:59:22 +0000
committerGerrit Code Review <review@openstack.org>2019-03-15 16:59:23 +0000
commitf944f60041dfbf19547d35f4abf3f18001a05930 (patch)
treeb712031a1e529c7416ee692b0700113ad7901642
parentc11f45bddae308ce92e36f404c0bd02797741112 (diff)
parentf1f4f892fe95f95128f8b872d4a3d32dc9cdb5fd (diff)
downloadironic-f944f60041dfbf19547d35f4abf3f18001a05930.tar.gz
Merge "Add Huawei iBMC driver support"
-rw-r--r--doc/source/admin/drivers.rst1
-rw-r--r--doc/source/admin/drivers/ibmc.rst119
-rw-r--r--doc/source/images/ironic_standalone_with_ibmc_driver.svg1309
-rw-r--r--driver-requirements.txt3
-rw-r--r--ironic/common/exception.py8
-rw-r--r--ironic/conf/__init__.py2
-rw-r--r--ironic/conf/ibmc.py35
-rw-r--r--ironic/drivers/ibmc.py40
-rw-r--r--ironic/drivers/modules/ibmc/__init__.py0
-rw-r--r--ironic/drivers/modules/ibmc/management.py237
-rw-r--r--ironic/drivers/modules/ibmc/mappings.py70
-rw-r--r--ironic/drivers/modules/ibmc/power.py145
-rw-r--r--ironic/drivers/modules/ibmc/utils.py177
-rw-r--r--ironic/drivers/modules/ibmc/vendor.py87
-rw-r--r--ironic/tests/unit/db/utils.py9
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/__init__.py0
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/base.py42
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/test_management.py276
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/test_power.py284
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/test_utils.py172
-rw-r--r--ironic/tests/unit/drivers/modules/ibmc/test_vendor.py60
-rw-r--r--ironic/tests/unit/drivers/test_ibmc.py47
-rw-r--r--ironic/tests/unit/drivers/third_party_driver_mock_specs.py7
-rw-r--r--ironic/tests/unit/drivers/third_party_driver_mocks.py43
-rw-r--r--releasenotes/notes/ibmc-driver-45fcf9f50ebf0193.yaml10
-rw-r--r--setup.cfg4
26 files changed, 3187 insertions, 0 deletions
diff --git a/doc/source/admin/drivers.rst b/doc/source/admin/drivers.rst
index 6eca9d392..91c92026e 100644
--- a/doc/source/admin/drivers.rst
+++ b/doc/source/admin/drivers.rst
@@ -18,6 +18,7 @@ Hardware Types
:maxdepth: 1
drivers/cimc
+ drivers/ibmc
drivers/idrac
drivers/ilo
drivers/ipmitool
diff --git a/doc/source/admin/drivers/ibmc.rst b/doc/source/admin/drivers/ibmc.rst
new file mode 100644
index 000000000..d7adb0dab
--- /dev/null
+++ b/doc/source/admin/drivers/ibmc.rst
@@ -0,0 +1,119 @@
+===============
+iBMC driver
+===============
+
+Overview
+========
+
+The ``ibmc`` driver is targeted for Huawei rack server 2288H V5, CH121 V5.
+The iBMC hardware type enables the user to take advantage of features of
+`Huawei iBMC`_ to control Huawei server.
+
+Prerequisites
+=============
+
+The `HUAWEI iBMC Client library`_ should be installed on the ironic conductor
+ node(s).
+
+For example, it can be installed with ``pip``::
+
+ sudo pip install python-ibmcclient
+
+Enabling the iBMC driver
+============================
+
+#. Add ``ibmc`` to the list of ``enabled_hardware_types``,
+ ``enabled_power_interfaces``, ``enabled_vendor_interfaces``
+ and ``enabled_management_interfaces`` in ``/etc/ironic/ironic.conf``. For example::
+
+ [DEFAULT]
+ ...
+ enabled_hardware_types = ibmc,ipmi
+ enabled_power_interfaces = ibmc,ipmitool
+ enabled_management_interfaces = ibmc,ipmitool
+ enabled_vendor_interfaces = ibmc
+
+#. Restart the ironic conductor service::
+
+ sudo service ironic-conductor restart
+
+ # Or, for RDO:
+ sudo systemctl restart openstack-ironic-conductor
+
+Registering a node with the iBMC driver
+===========================================
+
+Nodes configured to use the driver should have the ``driver`` property
+set to ``ibmc``.
+
+The following properties are specified in the node's ``driver_info``
+field:
+
+- ``ibmc_address``:
+
+ The URL address to the ibmc controller. It must
+ include the authority portion of the URL, and can
+ optionally include the scheme. If the scheme is
+ missing, https is assumed.
+ For example: https://ibmc.example.com. This is required.
+
+- ``ibmc_username``:
+
+ User account with admin/server-profile access
+ privilege. This is required.
+
+- ``ibmc_password``:
+
+ User account password. This is required.
+
+- ``ibmc_verify_ca``:
+
+ If ibmc_address has the **https** scheme, the
+ driver will use a secure (TLS_) connection when
+ talking to the ibmc controller. By default
+ (if this is set to True), the driver will try to
+ verify the host certificates. This can be set to
+ the path of a certificate file or directory with
+ trusted certificates that the driver will use for
+ verification. To disable verifying TLS_, set this
+ to False. This is optional.
+
+The ``openstack baremetal node create`` command can be used to enroll
+a node with the ``ibmc`` driver. For example:
+
+.. code-block:: bash
+
+ openstack baremetal node create --driver ibmc
+ --driver-info ibmc_address=https://example.com \
+ --driver-info ibmc_username=admin \
+ --driver-info ibmc_password=password
+
+For more information about enrolling nodes see :ref:`enrollment`
+in the install guide.
+
+Features of the ``ibmc`` hardware type
+=========================================
+
+Query boot up sequence
+^^^^^^^^^^^^^^^^^^^^^^
+
+The ``ibmc`` hardware type can query current boot up sequence from the
+bare metal node
+
+.. code-block:: bash
+
+ openstack baremetal node passthru call --http-method GET \
+ <node id or node name> boot_up_seq
+
+
+PXE Boot and iSCSI Deploy Process with Ironic Standalone Environment
+====================================================================
+
+.. figure:: ../../images/ironic_standalone_with_ibmc_driver.svg
+ :width: 960px
+ :align: left
+ :alt: Ironic standalone with iBMC driver node
+
+.. _Huawei iBMC: https://e.huawei.com/en/products/cloud-computing-dc/servers/accessories/ibmc
+.. _TLS: https://en.wikipedia.org/wiki/Transport_Layer_Security
+.. _HUAWEI iBMC Client library: https://pypi.org/project/python-ibmcclient/
diff --git a/doc/source/images/ironic_standalone_with_ibmc_driver.svg b/doc/source/images/ironic_standalone_with_ibmc_driver.svg
new file mode 100644
index 000000000..d2ef253e2
--- /dev/null
+++ b/doc/source/images/ironic_standalone_with_ibmc_driver.svg
@@ -0,0 +1,1309 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.2" width="210.06mm" height="296.93mm" viewBox="0 0 21006 29693" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
+ <defs class="ClipPathGroup">
+ <clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
+ <rect x="0" y="0" width="21006" height="29693"/>
+ </clipPath>
+ </defs>
+ <defs>
+ <font id="EmbeddedFont_1" horiz-adv-x="2048">
+ <font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/>
+ <missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
+ <glyph unicode="y" horiz-adv-x="1033" d="M 604,1 C 579,-64 553,-123 527,-175 500,-227 471,-272 438,-309 405,-346 369,-374 329,-394 289,-413 243,-423 191,-423 168,-423 147,-423 128,-423 109,-423 88,-420 67,-414 L 67,-279 C 80,-282 94,-284 110,-284 126,-284 140,-284 151,-284 204,-284 253,-264 298,-225 343,-186 383,-124 417,-38 L 434,5 5,1082 197,1082 425,484 C 432,466 440,442 451,412 461,382 471,352 482,322 492,292 501,265 509,241 517,217 522,202 523,196 525,203 530,218 538,240 545,261 554,285 564,312 573,339 583,366 593,393 603,420 611,444 618,464 L 830,1082 1020,1082 604,1 Z"/>
+ <glyph unicode="x" horiz-adv-x="1006" d="M 801,0 L 510,444 217,0 23,0 408,556 41,1082 240,1082 510,661 778,1082 979,1082 612,558 1002,0 801,0 Z"/>
+ <glyph unicode="w" horiz-adv-x="1509" d="M 1174,0 L 965,0 792,698 C 787,716 781,738 776,765 770,792 764,818 759,843 752,872 746,903 740,934 734,904 728,874 721,845 716,820 710,793 704,766 697,739 691,715 686,694 L 508,0 300,0 -3,1082 175,1082 358,347 C 363,332 367,313 372,291 377,268 381,246 386,225 391,200 396,175 401,149 406,174 412,199 418,223 423,244 429,265 434,286 439,307 444,325 448,339 L 644,1082 837,1082 1026,339 C 1031,322 1036,302 1041,280 1046,258 1051,237 1056,218 1061,195 1067,172 1072,149 1077,174 1083,199 1088,223 1093,244 1098,265 1103,288 1108,310 1112,330 1117,347 L 1308,1082 1484,1082 1174,0 Z"/>
+ <glyph unicode="v" horiz-adv-x="1033" d="M 613,0 L 400,0 7,1082 199,1082 437,378 C 442,363 447,346 454,325 460,304 466,282 473,259 480,236 486,215 492,194 497,173 502,155 506,141 510,155 515,173 522,194 528,215 534,236 541,258 548,280 555,302 562,323 569,344 575,361 580,376 L 826,1082 1017,1082 613,0 Z"/>
+ <glyph unicode="u" horiz-adv-x="874" d="M 314,1082 L 314,396 C 314,343 318,299 326,264 333,229 346,200 363,179 380,157 403,142 432,133 460,124 495,119 537,119 580,119 618,127 653,142 687,157 716,178 741,207 765,235 784,270 797,312 810,353 817,401 817,455 L 817,1082 997,1082 997,228 C 997,205 997,181 998,156 998,131 998,107 999,85 1000,62 1000,43 1001,27 1002,11 1002,3 1003,3 L 833,3 C 832,6 832,15 831,30 830,44 830,61 829,79 828,98 827,117 826,136 825,156 825,172 825,185 L 822,185 C 805,154 786,125 765,100 744,75 720,53 693,36 666,18 634,4 599,-6 564,-15 523,-20 476,-20 416,-20 364,-13 321,2 278,17 242,39 214,70 186,101 166,140 153,188 140,236 133,294 133,361 L 133,1082 314,1082 Z"/>
+ <glyph unicode="t" horiz-adv-x="531" d="M 554,8 C 527,1 499,-5 471,-10 442,-14 409,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 467,127 484,128 501,131 517,134 535,137 554,141 L 554,8 Z"/>
+ <glyph unicode="s" horiz-adv-x="901" d="M 950,299 C 950,248 940,203 921,164 901,124 872,91 835,64 798,37 752,16 698,2 643,-13 581,-20 511,-20 448,-20 392,-15 342,-6 291,4 247,20 209,41 171,62 139,91 114,126 88,161 69,203 57,254 L 216,285 C 231,227 263,185 311,158 359,131 426,117 511,117 550,117 585,120 618,125 650,130 678,140 701,153 724,166 743,183 756,205 769,226 775,253 775,285 775,318 767,345 752,366 737,387 715,404 688,418 661,432 628,444 589,455 550,465 507,476 460,489 417,500 374,513 331,527 288,541 250,560 216,583 181,606 153,634 132,668 111,702 100,745 100,796 100,895 135,970 206,1022 276,1073 378,1099 513,1099 632,1099 727,1078 798,1036 868,994 912,927 931,834 L 769,814 C 763,842 752,866 736,885 720,904 701,919 678,931 655,942 630,951 602,956 573,961 544,963 513,963 432,963 372,951 333,926 294,901 275,864 275,814 275,785 282,761 297,742 311,723 331,707 357,694 382,681 413,669 449,660 485,650 525,640 568,629 597,622 626,614 656,606 686,597 715,587 744,576 772,564 799,550 824,535 849,519 870,500 889,478 908,456 923,430 934,401 945,372 950,338 950,299 Z"/>
+ <glyph unicode="r" horiz-adv-x="530" d="M 142,0 L 142,830 C 142,853 142,876 142,900 141,923 141,946 140,968 139,990 139,1011 138,1030 137,1049 137,1067 136,1082 L 306,1082 C 307,1067 308,1049 309,1030 310,1010 311,990 312,969 313,948 313,929 314,910 314,891 314,874 314,861 L 318,861 C 331,902 344,938 359,969 373,999 390,1024 409,1044 428,1063 451,1078 478,1088 505,1097 537,1102 575,1102 590,1102 604,1101 617,1099 630,1096 641,1094 648,1092 L 648,927 C 636,930 622,933 606,935 590,936 572,937 552,937 511,937 476,928 447,909 418,890 394,865 376,832 357,799 344,759 335,714 326,668 322,618 322,564 L 322,0 142,0 Z"/>
+ <glyph unicode="q" horiz-adv-x="927" d="M 484,-20 C 347,-20 246,26 182,119 118,212 86,351 86,536 86,724 119,865 185,960 250,1055 350,1102 484,1102 529,1102 568,1098 603,1090 637,1082 668,1070 695,1055 722,1039 745,1019 766,996 786,973 804,945 821,914 L 823,914 C 823,931 824,949 825,970 826,990 827,1010 828,1028 829,1046 830,1061 831,1074 832,1087 834,1094 835,1094 L 1008,1094 C 1007,1083 1005,1053 1004,1005 1002,957 1001,889 1001,799 L 1001,-425 821,-425 821,14 C 821,31 821,49 822,68 822,87 822,104 823,121 824,140 824,159 825,178 L 823,178 C 806,144 787,115 766,90 745,65 720,44 693,28 666,11 635,-1 601,-9 566,-16 527,-20 484,-20 Z M 821,554 C 821,633 814,699 801,752 787,805 768,848 743,880 718,912 687,935 652,949 616,962 576,969 532,969 486,969 447,961 414,944 381,927 355,901 335,866 314,831 299,786 290,733 280,679 275,615 275,542 275,470 280,407 289,354 298,301 312,257 333,222 353,187 379,162 412,145 444,128 483,119 530,119 570,119 608,125 643,138 678,150 709,172 736,205 762,237 783,281 798,338 813,394 821,466 821,554 Z"/>
+ <glyph unicode="p" horiz-adv-x="953" d="M 1053,546 C 1053,464 1046,388 1033,319 1020,250 998,190 967,140 936,90 895,51 844,23 793,-6 730,-20 655,-20 578,-20 510,-5 452,24 394,53 350,101 319,168 L 314,168 C 315,167 315,161 316,150 316,139 316,126 317,110 317,94 317,76 318,57 318,37 318,17 318,-2 L 318,-425 138,-425 138,864 C 138,891 138,916 138,940 137,964 137,986 136,1005 135,1025 135,1042 134,1056 133,1070 133,1077 132,1077 L 306,1077 C 307,1075 308,1068 309,1057 310,1045 311,1031 312,1014 313,998 314,980 315,961 316,943 316,925 316,908 L 320,908 C 337,943 356,972 377,997 398,1021 423,1041 450,1057 477,1072 508,1084 542,1091 575,1098 613,1101 655,1101 730,1101 793,1088 844,1061 895,1034 936,997 967,949 998,900 1020,842 1033,774 1046,705 1053,629 1053,546 Z M 864,542 C 864,609 860,668 852,720 844,772 830,816 811,852 791,888 765,915 732,934 699,953 658,962 609,962 569,962 531,956 496,945 461,934 430,912 404,880 377,848 356,804 341,748 326,691 318,618 318,528 318,451 324,387 337,334 350,281 368,238 393,205 417,172 447,149 483,135 519,120 560,113 607,113 657,113 699,123 732,142 765,161 791,189 811,226 830,263 844,308 852,361 860,414 864,474 864,542 Z"/>
+ <glyph unicode="o" horiz-adv-x="980" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 490,-20 422,-9 363,14 304,37 254,71 213,118 172,165 140,223 119,294 97,364 86,447 86,542 86,915 248,1102 571,1102 655,1102 728,1090 789,1067 850,1044 900,1009 939,962 978,915 1006,857 1025,787 1044,717 1053,635 1053,542 Z M 864,542 C 864,626 858,695 845,750 832,805 813,848 788,881 763,914 732,937 696,950 660,963 619,969 574,969 528,969 487,962 450,949 413,935 381,912 355,879 329,846 309,802 296,747 282,692 275,624 275,542 275,458 282,389 297,334 312,279 332,235 358,202 383,169 414,146 449,133 484,120 522,113 563,113 609,113 651,120 688,133 725,146 757,168 783,201 809,234 829,278 843,333 857,388 864,458 864,542 Z"/>
+ <glyph unicode="n" horiz-adv-x="874" d="M 825,0 L 825,686 C 825,739 821,783 814,818 806,853 793,882 776,904 759,925 736,941 708,950 679,959 644,963 602,963 559,963 521,956 487,941 452,926 423,904 399,876 374,847 355,812 342,771 329,729 322,681 322,627 L 322,0 142,0 142,853 C 142,876 142,900 142,925 141,950 141,974 140,996 139,1019 139,1038 138,1054 137,1070 137,1078 136,1078 L 306,1078 C 307,1075 307,1066 308,1052 309,1037 310,1021 311,1002 312,984 312,965 313,945 314,926 314,910 314,897 L 317,897 C 334,928 353,957 374,982 395,1007 419,1029 446,1047 473,1064 505,1078 540,1088 575,1097 616,1102 663,1102 723,1102 775,1095 818,1080 861,1065 897,1043 925,1012 953,981 974,942 987,894 1000,845 1006,788 1006,721 L 1006,0 825,0 Z"/>
+ <glyph unicode="m" horiz-adv-x="1457" d="M 768,0 L 768,686 C 768,739 765,783 758,818 751,853 740,882 725,904 709,925 688,941 663,950 638,959 607,963 570,963 532,963 498,956 467,941 436,926 410,904 389,876 367,847 350,812 339,771 327,729 321,681 321,627 L 321,0 142,0 142,853 C 142,876 142,900 142,925 141,950 141,974 140,996 139,1019 139,1038 138,1054 137,1070 137,1078 136,1078 L 306,1078 C 307,1075 307,1066 308,1052 309,1037 310,1021 311,1002 312,984 312,965 313,945 314,926 314,910 314,897 L 317,897 C 333,928 350,957 369,982 388,1007 410,1029 435,1047 460,1064 488,1078 521,1088 553,1097 590,1102 633,1102 715,1102 780,1086 828,1053 875,1020 908,968 927,897 L 930,897 C 946,928 964,957 984,982 1004,1007 1027,1029 1054,1047 1081,1064 1111,1078 1144,1088 1177,1097 1215,1102 1258,1102 1313,1102 1360,1095 1400,1080 1439,1065 1472,1043 1497,1012 1522,981 1541,942 1553,894 1565,845 1571,788 1571,721 L 1571,0 1393,0 1393,686 C 1393,739 1390,783 1383,818 1376,853 1365,882 1350,904 1334,925 1313,941 1288,950 1263,959 1232,963 1195,963 1157,963 1123,956 1092,942 1061,927 1035,906 1014,878 992,850 975,815 964,773 952,731 946,682 946,627 L 946,0 768,0 Z"/>
+ <glyph unicode="l" horiz-adv-x="187" d="M 138,0 L 138,1484 318,1484 318,0 138,0 Z"/>
+ <glyph unicode="k" horiz-adv-x="901" d="M 816,0 L 450,494 318,385 318,0 138,0 138,1484 318,1484 318,557 793,1082 1004,1082 565,617 1027,0 816,0 Z"/>
+ <glyph unicode="i" horiz-adv-x="187" d="M 137,1312 L 137,1484 317,1484 317,1312 137,1312 Z M 137,0 L 137,1082 317,1082 317,0 137,0 Z"/>
+ <glyph unicode="h" horiz-adv-x="874" d="M 317,897 C 337,934 359,965 382,991 405,1016 431,1037 459,1054 487,1071 518,1083 551,1091 584,1098 622,1102 663,1102 732,1102 789,1093 834,1074 878,1055 913,1029 939,996 964,962 982,922 992,875 1001,828 1006,777 1006,721 L 1006,0 825,0 825,686 C 825,732 822,772 817,807 811,842 800,871 784,894 768,917 745,934 716,946 687,957 649,963 602,963 559,963 521,955 487,940 452,925 423,903 399,875 374,847 355,813 342,773 329,733 322,688 322,638 L 322,0 142,0 142,1484 322,1484 322,1098 C 322,1076 322,1054 321,1032 320,1010 320,990 319,971 318,952 317,937 316,924 315,911 315,902 314,897 L 317,897 Z"/>
+ <glyph unicode="g" horiz-adv-x="927" d="M 548,-425 C 486,-425 431,-419 383,-406 335,-393 294,-375 260,-352 226,-328 198,-300 177,-267 156,-234 140,-198 131,-158 L 312,-132 C 324,-182 351,-220 392,-248 433,-274 486,-288 553,-288 594,-288 631,-282 664,-271 697,-260 726,-241 749,-217 772,-191 790,-159 803,-119 816,-79 822,-30 822,27 L 822,201 820,201 C 807,174 790,148 771,123 751,98 727,75 699,56 670,37 637,21 600,10 563,-2 520,-8 472,-8 403,-8 345,4 296,27 247,50 207,84 176,130 145,176 122,233 108,302 93,370 86,449 86,539 86,626 93,704 108,773 122,842 145,901 178,950 210,998 252,1035 304,1061 355,1086 418,1099 492,1099 569,1099 635,1082 692,1047 748,1012 791,962 822,897 L 824,897 C 824,914 825,933 826,953 827,974 828,994 829,1012 830,1031 831,1046 832,1060 833,1073 835,1080 836,1080 L 1007,1080 C 1006,1074 1006,1064 1005,1050 1004,1035 1004,1018 1003,998 1002,978 1002,956 1002,932 1001,907 1001,882 1001,856 L 1001,30 C 1001,-121 964,-234 890,-311 815,-387 701,-425 548,-425 Z M 822,541 C 822,616 814,681 798,735 781,788 760,832 733,866 706,900 676,925 642,941 607,957 572,965 536,965 490,965 451,957 418,941 385,925 357,900 336,866 314,831 298,787 288,734 277,680 272,616 272,541 272,463 277,398 288,345 298,292 314,249 335,216 356,183 383,160 416,146 449,132 488,125 533,125 569,125 604,133 639,148 673,163 704,188 731,221 758,254 780,297 797,350 814,403 822,466 822,541 Z"/>
+ <glyph unicode="f" horiz-adv-x="557" d="M 361,951 L 361,0 181,0 181,951 29,951 29,1082 181,1082 181,1204 C 181,1243 185,1280 192,1314 199,1347 213,1377 233,1402 252,1427 279,1446 313,1461 347,1475 391,1482 445,1482 466,1482 489,1481 512,1479 535,1477 555,1474 572,1470 L 572,1333 C 561,1335 548,1337 533,1339 518,1340 504,1341 492,1341 465,1341 444,1337 427,1330 410,1323 396,1312 387,1299 377,1285 370,1268 367,1248 363,1228 361,1205 361,1179 L 361,1082 572,1082 572,951 361,951 Z"/>
+ <glyph unicode="e" horiz-adv-x="980" d="M 276,503 C 276,446 282,394 294,347 305,299 323,258 348,224 372,189 403,163 441,144 479,125 525,115 578,115 656,115 719,131 766,162 813,193 844,233 861,281 L 1019,236 C 1008,206 992,176 972,146 951,115 924,88 890,64 856,39 814,19 763,4 712,-12 650,-20 578,-20 418,-20 296,28 213,123 129,218 87,360 87,548 87,649 100,735 125,806 150,876 185,933 229,977 273,1021 324,1053 383,1073 442,1092 504,1102 571,1102 662,1102 738,1087 799,1058 860,1029 909,988 946,937 983,885 1009,824 1025,754 1040,684 1048,608 1048,527 L 1048,503 276,503 Z M 862,641 C 852,755 823,838 775,891 727,943 658,969 568,969 538,969 507,964 474,955 441,945 410,928 382,903 354,878 330,845 311,803 292,760 281,706 278,641 L 862,641 Z"/>
+ <glyph unicode="d" horiz-adv-x="927" d="M 821,174 C 788,105 744,55 689,25 634,-5 565,-20 484,-20 347,-20 247,26 183,118 118,210 86,349 86,536 86,913 219,1102 484,1102 566,1102 634,1087 689,1057 744,1027 788,979 821,914 L 823,914 C 823,921 823,931 823,946 822,960 822,975 822,991 821,1006 821,1021 821,1035 821,1049 821,1059 821,1065 L 821,1484 1001,1484 1001,219 C 1001,193 1001,168 1002,143 1002,119 1002,97 1003,77 1004,57 1004,40 1005,26 1006,11 1006,4 1007,4 L 835,4 C 834,11 833,20 832,32 831,44 830,58 829,73 828,89 827,105 826,123 825,140 825,157 825,174 L 821,174 Z M 275,542 C 275,467 280,403 289,350 298,297 313,253 334,219 355,184 381,159 413,143 445,127 484,119 530,119 577,119 619,127 656,142 692,157 722,182 747,217 771,251 789,296 802,351 815,406 821,474 821,554 821,631 815,696 802,749 789,802 771,844 746,877 721,910 691,933 656,948 620,962 579,969 532,969 488,969 450,961 418,946 386,931 359,906 338,872 317,838 301,794 291,740 280,685 275,619 275,542 Z"/>
+ <glyph unicode="c" horiz-adv-x="901" d="M 275,546 C 275,484 280,427 289,375 298,323 313,278 334,241 355,203 384,174 419,153 454,132 497,122 548,122 612,122 666,139 709,173 752,206 778,258 788,328 L 970,328 C 964,283 951,239 931,197 911,155 884,118 850,86 815,54 773,28 724,9 675,-10 618,-20 553,-20 468,-20 396,-6 337,23 278,52 230,91 193,142 156,192 129,251 112,320 95,388 87,462 87,542 87,615 93,679 105,735 117,790 134,839 156,881 177,922 203,957 232,986 261,1014 293,1037 328,1054 362,1071 398,1083 436,1091 474,1098 512,1102 551,1102 612,1102 666,1094 713,1077 760,1060 801,1038 836,1009 870,980 898,945 919,906 940,867 955,824 964,779 L 779,765 C 770,825 746,873 708,908 670,943 616,961 546,961 495,961 452,953 418,936 383,919 355,893 334,859 313,824 298,781 289,729 280,677 275,616 275,546 Z"/>
+ <glyph unicode="b" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 573,-20 505,-5 451,25 396,54 352,102 318,168 L 316,168 C 316,150 316,132 315,113 314,94 313,77 312,61 311,45 310,31 309,19 308,8 307,2 306,2 L 132,2 C 133,8 133,18 134,32 135,47 135,64 136,84 137,104 137,126 138,150 138,174 138,199 138,225 L 138,1484 318,1484 318,1061 C 318,1041 318,1022 318,1004 317,985 317,969 316,955 315,938 315,923 314,908 L 318,908 C 351,977 396,1027 451,1057 506,1087 574,1102 655,1102 792,1102 892,1056 957,964 1021,872 1053,733 1053,546 Z M 864,540 C 864,615 859,679 850,732 841,785 826,829 805,864 784,898 758,923 726,939 694,955 655,963 609,963 562,963 520,955 484,940 447,925 417,900 393,866 368,832 350,787 337,732 324,677 318,609 318,529 318,452 324,387 337,334 350,281 368,239 393,206 417,173 447,149 483,135 519,120 560,113 607,113 651,113 689,121 721,136 753,151 780,176 801,210 822,244 838,288 849,343 859,397 864,463 864,540 Z"/>
+ <glyph unicode="a" horiz-adv-x="1060" d="M 414,-20 C 305,-20 224,9 169,66 114,124 87,203 87,303 87,375 101,434 128,480 155,526 190,562 234,588 277,614 327,632 383,642 439,652 496,657 554,657 L 797,657 797,717 C 797,762 792,800 783,832 774,863 759,889 740,908 721,928 697,942 668,951 639,960 604,965 565,965 530,965 499,963 471,958 443,953 419,944 398,931 377,918 361,900 348,878 335,855 327,827 323,793 L 135,810 C 142,853 154,892 173,928 192,963 218,994 253,1020 287,1046 330,1066 382,1081 433,1095 496,1102 569,1102 705,1102 807,1071 876,1009 945,946 979,856 979,738 L 979,272 C 979,219 986,179 1000,152 1014,125 1041,111 1080,111 1090,111 1100,112 1110,113 1120,114 1130,116 1139,118 L 1139,6 C 1116,1 1094,-3 1072,-6 1049,-9 1025,-10 1000,-10 966,-10 937,-5 913,4 888,13 868,26 853,45 838,63 826,86 818,113 810,140 805,171 803,207 L 797,207 C 778,172 757,141 734,113 711,85 684,61 653,42 622,22 588,7 549,-4 510,-15 465,-20 414,-20 Z M 455,115 C 512,115 563,125 606,146 649,167 684,194 713,226 741,259 762,294 776,332 790,371 797,408 797,443 L 797,531 600,531 C 556,531 514,528 475,522 435,517 400,506 370,489 340,472 316,449 299,418 281,388 272,349 272,300 272,241 288,195 320,163 351,131 396,115 455,115 Z"/>
+ <glyph unicode="_" horiz-adv-x="1218" d="M -31,-407 L -31,-277 1162,-277 1162,-407 -31,-407 Z"/>
+ <glyph unicode="X" horiz-adv-x="1298" d="M 1112,0 L 689,616 257,0 46,0 582,732 87,1409 298,1409 690,856 1071,1409 1282,1409 800,739 1323,0 1112,0 Z"/>
+ <glyph unicode="W" horiz-adv-x="1932" d="M 1511,0 L 1283,0 1039,895 C 1032,920 1024,950 1016,985 1007,1020 1000,1053 993,1084 985,1121 977,1158 969,1196 960,1157 952,1120 944,1083 937,1051 929,1018 921,984 913,950 905,920 898,895 L 652,0 424,0 9,1409 208,1409 461,514 C 472,472 483,430 494,389 504,348 513,311 520,278 529,239 537,203 544,168 554,214 564,259 575,304 580,323 584,342 589,363 594,384 599,404 604,424 609,444 614,463 619,482 624,500 628,517 632,532 L 877,1409 1060,1409 1305,532 C 1309,517 1314,500 1319,482 1324,463 1329,444 1334,425 1339,405 1343,385 1348,364 1353,343 1357,324 1362,305 1373,260 1383,215 1393,168 1394,168 1397,180 1402,203 1407,226 1414,254 1422,289 1430,324 1439,361 1449,402 1458,442 1468,479 1478,514 L 1727,1409 1926,1409 1511,0 Z"/>
+ <glyph unicode="V" horiz-adv-x="1377" d="M 782,0 L 584,0 9,1409 210,1409 600,417 C 610,387 620,357 630,328 640,298 649,271 657,248 666,221 675,194 684,168 692,193 701,219 710,246 718,269 727,296 737,325 746,354 757,385 768,417 L 1156,1409 1357,1409 782,0 Z"/>
+ <glyph unicode="U" horiz-adv-x="1192" d="M 731,-20 C 654,-20 580,-10 511,11 442,32 381,64 329,108 276,151 235,207 204,274 173,341 158,420 158,512 L 158,1409 349,1409 349,528 C 349,457 359,396 378,347 397,297 423,256 457,225 491,194 531,171 578,157 624,142 675,135 730,135 785,135 836,142 885,157 934,172 976,195 1013,227 1050,259 1079,301 1100,353 1121,404 1131,467 1131,541 L 1131,1409 1321,1409 1321,530 C 1321,436 1306,355 1275,286 1244,217 1201,159 1148,114 1095,69 1032,35 961,13 889,-9 812,-20 731,-20 Z"/>
+ <glyph unicode="T" horiz-adv-x="1192" d="M 720,1253 L 720,0 530,0 530,1253 46,1253 46,1409 1204,1409 1204,1253 720,1253 Z"/>
+ <glyph unicode="S" horiz-adv-x="1192" d="M 1272,389 C 1272,330 1261,275 1238,225 1215,175 1179,132 1131,96 1083,59 1023,31 950,11 877,-10 790,-20 690,-20 515,-20 378,11 280,72 182,133 120,222 93,338 L 278,375 C 287,338 302,305 321,275 340,245 367,219 400,198 433,176 473,159 522,147 571,135 629,129 697,129 754,129 806,134 853,144 900,153 941,168 975,188 1009,208 1036,234 1055,266 1074,297 1083,335 1083,379 1083,425 1073,462 1052,491 1031,520 1001,543 963,562 925,581 880,596 827,609 774,622 716,635 652,650 613,659 573,668 534,679 494,689 456,701 420,716 383,730 349,747 317,766 285,785 257,809 234,836 211,863 192,894 179,930 166,965 159,1006 159,1053 159,1120 173,1177 200,1225 227,1272 264,1311 312,1342 360,1373 417,1395 482,1409 547,1423 618,1430 694,1430 781,1430 856,1423 918,1410 980,1396 1032,1375 1075,1348 1118,1321 1152,1287 1178,1247 1203,1206 1224,1159 1239,1106 L 1051,1073 C 1042,1107 1028,1137 1011,1164 993,1191 970,1213 941,1231 912,1249 878,1263 837,1272 796,1281 747,1286 692,1286 627,1286 572,1280 528,1269 483,1257 448,1241 421,1221 394,1201 374,1178 363,1151 351,1124 345,1094 345,1063 345,1021 356,987 377,960 398,933 426,910 462,892 498,874 540,859 587,847 634,835 685,823 738,811 781,801 825,791 868,781 911,770 952,758 991,744 1030,729 1067,712 1102,693 1136,674 1166,650 1191,622 1216,594 1236,561 1251,523 1265,485 1272,440 1272,389 Z"/>
+ <glyph unicode="R" horiz-adv-x="1244" d="M 1164,0 L 798,585 359,585 359,0 168,0 168,1409 831,1409 C 911,1409 982,1400 1044,1382 1105,1363 1157,1337 1199,1302 1241,1267 1273,1225 1295,1175 1317,1125 1328,1069 1328,1006 1328,961 1322,917 1309,874 1296,831 1275,791 1247,755 1219,719 1183,688 1140,662 1097,636 1045,618 984,607 L 1384,0 1164,0 Z M 1136,1004 C 1136,1047 1129,1084 1114,1115 1099,1146 1078,1173 1050,1194 1022,1215 988,1230 948,1241 908,1251 863,1256 812,1256 L 359,1256 359,736 820,736 C 875,736 922,743 962,757 1002,770 1035,789 1061,813 1086,837 1105,865 1118,898 1130,931 1136,966 1136,1004 Z"/>
+ <glyph unicode="P" horiz-adv-x="1112" d="M 1258,985 C 1258,924 1248,867 1228,814 1207,761 1177,715 1137,676 1096,637 1046,606 985,583 924,560 854,549 773,549 L 359,549 359,0 168,0 168,1409 761,1409 C 844,1409 917,1399 979,1379 1041,1358 1093,1330 1134,1293 1175,1256 1206,1211 1227,1159 1248,1106 1258,1048 1258,985 Z M 1066,983 C 1066,1072 1039,1140 984,1187 929,1233 847,1256 738,1256 L 359,1256 359,700 746,700 C 856,700 937,724 989,773 1040,822 1066,892 1066,983 Z"/>
+ <glyph unicode="O" horiz-adv-x="1430" d="M 1495,711 C 1495,601 1479,501 1448,411 1416,321 1370,244 1310,180 1250,116 1177,67 1090,32 1003,-3 905,-20 795,-20 679,-20 577,-2 490,35 403,71 330,122 272,187 214,252 170,329 141,418 112,507 97,605 97,711 97,821 112,920 143,1009 174,1098 219,1173 278,1236 337,1298 411,1346 498,1380 585,1413 684,1430 797,1430 909,1430 1009,1413 1096,1379 1183,1345 1256,1297 1315,1234 1374,1171 1418,1096 1449,1007 1480,918 1495,820 1495,711 Z M 1300,711 C 1300,796 1289,873 1268,942 1246,1011 1214,1071 1172,1120 1129,1169 1077,1207 1014,1234 951,1261 879,1274 797,1274 713,1274 639,1261 576,1234 513,1207 460,1169 418,1120 375,1071 344,1011 323,942 302,873 291,796 291,711 291,626 302,549 324,479 345,408 377,348 420,297 462,246 515,206 578,178 641,149 713,135 795,135 883,135 959,149 1023,178 1086,207 1139,247 1180,298 1221,349 1251,409 1271,480 1290,551 1300,628 1300,711 Z"/>
+ <glyph unicode="N" horiz-adv-x="1165" d="M 1082,0 L 328,1200 C 329,1167 331,1135 333,1103 334,1076 336,1047 337,1017 338,986 338,959 338,936 L 338,0 168,0 168,1409 390,1409 1152,201 C 1150,234 1148,266 1146,299 1145,327 1143,358 1142,391 1141,424 1140,455 1140,485 L 1140,1409 1312,1409 1312,0 1082,0 Z"/>
+ <glyph unicode="M" horiz-adv-x="1377" d="M 1366,0 L 1366,940 C 1366,974 1366,1009 1367,1044 1368,1079 1369,1112 1370,1141 1371,1175 1373,1208 1375,1240 1366,1206 1356,1172 1346,1139 1337,1110 1328,1080 1318,1048 1307,1015 1297,986 1287,960 L 923,0 789,0 420,960 C 416,970 412,982 408,995 403,1008 399,1023 394,1038 389,1053 384,1068 379,1084 374,1099 369,1115 364,1130 353,1165 342,1202 331,1240 332,1203 333,1166 334,1129 335,1098 336,1065 337,1031 338,996 338,966 338,940 L 338,0 168,0 168,1409 419,1409 794,432 C 799,419 804,402 811,381 818,360 824,338 830,316 836,294 842,273 847,254 852,234 855,219 857,208 859,219 863,234 868,254 873,274 880,295 887,317 894,339 900,360 907,381 914,402 920,419 925,432 L 1293,1409 1538,1409 1538,0 1366,0 Z"/>
+ <glyph unicode="I" horiz-adv-x="213" d="M 189,0 L 189,1409 380,1409 380,0 189,0 Z"/>
+ <glyph unicode="H" horiz-adv-x="1165" d="M 1121,0 L 1121,653 359,653 359,0 168,0 168,1409 359,1409 359,813 1121,813 1121,1409 1312,1409 1312,0 1121,0 Z"/>
+ <glyph unicode="F" horiz-adv-x="1006" d="M 359,1253 L 359,729 1145,729 1145,571 359,571 359,0 168,0 168,1409 1169,1409 1169,1253 359,1253 Z"/>
+ <glyph unicode="E" horiz-adv-x="1138" d="M 168,0 L 168,1409 1237,1409 1237,1253 359,1253 359,801 1177,801 1177,647 359,647 359,156 1278,156 1278,0 168,0 Z"/>
+ <glyph unicode="D" horiz-adv-x="1218" d="M 1381,719 C 1381,602 1363,498 1328,409 1293,319 1244,244 1183,184 1122,123 1049,78 966,47 882,16 792,0 695,0 L 168,0 168,1409 634,1409 C 743,1409 843,1396 935,1369 1026,1342 1105,1300 1171,1244 1237,1187 1289,1116 1326,1029 1363,942 1381,839 1381,719 Z M 1189,719 C 1189,814 1175,896 1148,964 1121,1031 1082,1087 1033,1130 984,1173 925,1205 856,1226 787,1246 712,1256 630,1256 L 359,1256 359,153 673,153 C 747,153 816,165 879,189 942,213 996,249 1042,296 1088,343 1124,402 1150,473 1176,544 1189,626 1189,719 Z"/>
+ <glyph unicode="C" horiz-adv-x="1324" d="M 792,1274 C 712,1274 641,1261 580,1234 518,1207 466,1169 425,1120 383,1071 351,1011 330,942 309,873 298,796 298,711 298,626 310,549 333,479 356,408 389,348 432,297 475,246 527,207 590,179 652,151 722,137 800,137 855,137 905,144 950,159 995,173 1035,193 1072,219 1108,245 1140,276 1169,312 1198,347 1223,387 1245,430 L 1401,352 C 1376,299 1344,250 1307,205 1270,160 1226,120 1176,87 1125,54 1068,28 1005,9 941,-10 870,-20 791,-20 677,-20 577,-2 492,35 406,71 334,122 277,187 219,252 176,329 147,418 118,507 104,605 104,711 104,821 119,920 150,1009 180,1098 224,1173 283,1236 341,1298 413,1346 498,1380 583,1413 681,1430 790,1430 940,1430 1065,1401 1166,1342 1267,1283 1341,1196 1388,1081 L 1207,1021 C 1194,1054 1176,1086 1153,1117 1130,1147 1102,1174 1068,1197 1034,1220 994,1239 949,1253 903,1267 851,1274 792,1274 Z"/>
+ <glyph unicode="B" horiz-adv-x="1112" d="M 1258,397 C 1258,326 1244,265 1216,215 1188,164 1150,123 1103,92 1056,60 1001,37 938,22 875,7 809,0 740,0 L 168,0 168,1409 680,1409 C 758,1409 828,1403 889,1390 950,1377 1002,1356 1045,1328 1088,1300 1120,1265 1143,1222 1165,1179 1176,1127 1176,1067 1176,1028 1171,991 1160,956 1149,921 1132,890 1110,862 1087,833 1059,809 1026,789 992,768 953,753 908,743 965,736 1015,723 1059,704 1102,685 1139,660 1168,630 1197,600 1220,565 1235,526 1250,486 1258,443 1258,397 Z M 984,1044 C 984,1120 958,1174 906,1207 854,1240 779,1256 680,1256 L 359,1256 359,810 680,810 C 736,810 783,816 822,827 861,838 892,853 916,874 940,894 957,918 968,947 979,976 984,1008 984,1044 Z M 1065,412 C 1065,457 1057,495 1041,526 1024,557 1001,583 970,603 939,623 903,638 860,647 817,656 768,661 715,661 L 359,661 359,153 730,153 C 779,153 824,157 865,165 906,173 941,187 971,207 1000,227 1023,254 1040,287 1057,320 1065,362 1065,412 Z"/>
+ <glyph unicode="A" horiz-adv-x="1377" d="M 1167,0 L 1006,412 364,412 202,0 4,0 579,1409 796,1409 1362,0 1167,0 Z M 768,1026 C 757,1053 747,1080 738,1107 728,1134 719,1159 712,1182 705,1204 699,1223 694,1238 689,1253 686,1262 685,1265 684,1262 681,1252 676,1237 671,1222 665,1203 658,1180 650,1157 641,1132 632,1105 622,1078 612,1051 602,1024 L 422,561 949,561 768,1026 Z"/>
+ <glyph unicode="2" horiz-adv-x="954" d="M 103,0 L 103,127 C 137,205 179,274 228,334 277,393 328,447 382,496 436,544 490,589 543,630 596,671 643,713 686,754 729,795 763,839 790,884 816,929 829,981 829,1038 829,1078 823,1113 811,1144 799,1174 782,1199 759,1220 736,1241 709,1256 678,1267 646,1277 611,1282 572,1282 536,1282 502,1277 471,1267 439,1257 411,1242 386,1222 361,1202 341,1177 326,1148 310,1118 300,1083 295,1044 L 111,1061 C 117,1112 131,1159 153,1204 175,1249 205,1288 244,1322 283,1355 329,1382 384,1401 438,1420 501,1430 572,1430 642,1430 704,1422 759,1405 814,1388 860,1364 898,1331 935,1298 964,1258 984,1210 1004,1162 1014,1107 1014,1044 1014,997 1006,952 989,909 972,866 949,826 921,787 892,748 859,711 822,675 785,639 746,604 705,570 664,535 623,501 582,468 541,434 502,400 466,366 429,332 397,298 368,263 339,228 317,191 301,153 L 1036,153 1036,0 103,0 Z"/>
+ <glyph unicode="1" horiz-adv-x="927" d="M 156,0 L 156,153 515,153 515,1237 197,1010 197,1180 530,1409 696,1409 696,153 1039,153 1039,0 156,0 Z"/>
+ <glyph unicode="." horiz-adv-x="213" d="M 187,0 L 187,219 382,219 382,0 187,0 Z"/>
+ <glyph unicode="," horiz-adv-x="239" d="M 385,219 L 385,51 C 385,16 384,-16 381,-46 378,-74 373,-101 366,-127 359,-151 351,-175 342,-197 332,-219 320,-241 307,-262 L 184,-262 C 214,-219 237,-175 254,-131 270,-87 278,-43 278,0 L 190,0 190,219 385,219 Z"/>
+ <glyph unicode=")" horiz-adv-x="557" d="M 555,528 C 555,435 548,346 534,262 520,177 498,96 468,18 438,-60 400,-136 353,-209 306,-282 251,-354 186,-424 L 12,-424 C 75,-354 129,-282 175,-209 220,-136 258,-60 287,19 316,98 338,179 353,264 367,349 374,437 374,530 374,623 367,711 353,796 338,881 316,962 287,1041 258,1119 220,1195 175,1269 129,1342 75,1414 12,1484 L 186,1484 C 251,1414 306,1342 353,1269 400,1196 438,1120 468,1042 498,964 520,883 534,798 548,713 555,625 555,532 L 555,528 Z"/>
+ <glyph unicode="(" horiz-adv-x="583" d="M 127,532 C 127,625 134,713 148,798 162,883 184,964 214,1042 244,1120 282,1196 329,1269 376,1342 431,1414 496,1484 L 670,1484 C 607,1414 553,1342 508,1269 462,1195 424,1119 395,1041 366,962 344,881 330,796 315,711 308,623 308,530 308,437 315,349 330,264 344,179 366,98 395,19 424,-60 462,-136 508,-209 553,-282 607,-354 670,-424 L 496,-424 C 431,-354 376,-282 329,-209 282,-136 244,-60 214,18 184,96 162,177 148,262 134,346 127,435 127,528 L 127,532 Z"/>
+ <glyph unicode=" " horiz-adv-x="556"/>
+ </font>
+ </defs>
+ <defs class="TextShapeIndex">
+ <g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28 id29 id30 id31 id32 id33 id34 id35 id36 id37 id38 id39 id40 id41 id42 id43 id44 id45 id46 id47 id48 id49 id50 id51 id52 id53 id54 id55 id56 id57 id58"/>
+ </defs>
+ <defs class="EmbeddedBulletChars">
+ <g id="bullet-char-template(57356)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
+ </g>
+ <g id="bullet-char-template(57354)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
+ </g>
+ <g id="bullet-char-template(10146)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
+ </g>
+ <g id="bullet-char-template(10132)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
+ </g>
+ <g id="bullet-char-template(10007)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
+ </g>
+ <g id="bullet-char-template(10004)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
+ </g>
+ <g id="bullet-char-template(9679)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
+ </g>
+ <g id="bullet-char-template(8226)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
+ </g>
+ <g id="bullet-char-template(8211)" transform="scale(0.00048828125,-0.00048828125)">
+ <path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
+ </g>
+ </defs>
+ <defs class="TextEmbeddedBitmaps"/>
+ <g>
+ <g id="id2" class="Master_Slide">
+ <g id="bg-id2" class="Background">
+ <path fill="rgb(255,255,255)" stroke="none" d="M 10503,29692 L 0,29692 0,0 21005,0 21005,29692 10503,29692 Z"/>
+ </g>
+ <g id="bo-id2" class="BackgroundObjects"/>
+ </g>
+ </g>
+ <g class="SlideGroup">
+ <g>
+ <g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
+ <g class="Page">
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id3">
+ <rect class="BoundingBox" stroke="none" fill="none" x="4766" y="1239" width="2822" height="894"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 4967,1440 L 7586,1440 7586,2131 4967,2131 4967,1440 4967,1440 Z M 4967,1440 L 4967,1440 Z M 7586,2131 L 7586,2131 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 4967,1440 L 7586,1440 7586,2131 4967,2131 4967,1440 4967,1440 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 4967,1440 L 4967,1440 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 7586,2131 L 7586,2131 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="5995" y="1906"><tspan fill="rgb(128,128,128)" stroke="none">API</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 4767,1240 L 7386,1240 7386,1931 4767,1931 4767,1240 4767,1240 Z M 4767,1240 L 4767,1240 Z M 7386,1931 L 7386,1931 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 4767,1240 L 7386,1240 7386,1931 4767,1931 4767,1240 4767,1240 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 4767,1240 L 4767,1240 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 7386,1931 L 7386,1931 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="5795" y="1706"><tspan fill="rgb(0,0,0)" stroke="none">API</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id4">
+ <rect class="BoundingBox" stroke="none" fill="none" x="6059" y="1929" width="45" height="24727"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6102,1930 L 6102,2082"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6102,2133 L 6101,2285"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6101,2336 L 6101,2488"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6101,2539 L 6101,2691"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6101,2742 L 6100,2894"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6100,2945 L 6100,3097"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6100,3148 L 6100,3300"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6100,3351 L 6099,3503"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6099,3554 L 6099,3706"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6099,3757 L 6099,3909"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6099,3960 L 6098,4112"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6098,4163 L 6098,4315"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6098,4366 L 6098,4518"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6098,4569 L 6097,4721"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6097,4772 L 6097,4924"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6097,4975 L 6097,5127"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6096,5178 L 6096,5330"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6096,5381 L 6096,5533"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6096,5584 L 6096,5736"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6095,5787 L 6095,5939"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6095,5990 L 6095,6142"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6095,6193 L 6095,6345"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6094,6396 L 6094,6548"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6094,6599 L 6094,6751"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6094,6802 L 6093,6954"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6093,7005 L 6093,7157"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6093,7208 L 6093,7360"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6093,7411 L 6092,7563"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6092,7614 L 6092,7766"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6092,7817 L 6092,7969"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6092,8020 L 6091,8172"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6091,8223 L 6091,8375"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6091,8426 L 6091,8578"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6091,8629 L 6090,8781"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6090,8832 L 6090,8984"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6090,9035 L 6090,9187"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6090,9238 L 6089,9390"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6089,9441 L 6089,9593"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6089,9644 L 6089,9796"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6089,9847 L 6088,9999"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6088,10050 L 6088,10202"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6088,10253 L 6088,10405"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6088,10456 L 6087,10608"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6087,10659 L 6087,10811"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6087,10862 L 6087,11014"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6086,11065 L 6086,11217"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6086,11268 L 6086,11420"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6086,11471 L 6086,11623"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6085,11674 L 6085,11826"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6085,11877 L 6085,12029"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6085,12080 L 6084,12232"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6084,12283 L 6084,12435"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6084,12486 L 6084,12638"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6084,12689 L 6083,12841"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6083,12892 L 6083,13044"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6083,13095 L 6083,13247"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6083,13298 L 6082,13450"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6082,13501 L 6082,13653"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6082,13704 L 6082,13856"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6082,13907 L 6081,14059"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6081,14110 L 6081,14262"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6081,14313 L 6081,14465"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6081,14516 L 6080,14668"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6080,14719 L 6080,14871"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6080,14922 L 6080,15074"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6080,15125 L 6079,15277"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6079,15328 L 6079,15480"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6079,15531 L 6079,15683"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6079,15734 L 6078,15886"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6078,15937 L 6078,16089"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6078,16140 L 6078,16292"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6078,16343 L 6077,16495"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6077,16546 L 6077,16698"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6077,16749 L 6077,16901"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6076,16952 L 6076,17104"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6076,17155 L 6076,17307"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6076,17358 L 6076,17510"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6075,17561 L 6075,17713"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6075,17764 L 6075,17916"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6075,17967 L 6074,18119"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6074,18170 L 6074,18322"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6074,18373 L 6074,18525"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6074,18576 L 6073,18728"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6073,18779 L 6073,18931"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6073,18982 L 6073,19134"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6073,19185 L 6072,19337"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6072,19388 L 6072,19540"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6072,19591 L 6072,19743"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6072,19794 L 6071,19946"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6071,19997 L 6071,20149"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6071,20200 L 6071,20352"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6071,20403 L 6070,20555"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6070,20606 L 6070,20758"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6070,20809 L 6070,20961"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6070,21012 L 6069,21164"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6069,21215 L 6069,21367"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6069,21418 L 6069,21570"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6069,21621 L 6068,21773"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6068,21824 L 6068,21976"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6068,22027 L 6068,22179"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6068,22230 L 6067,22382"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6067,22433 L 6067,22585"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6067,22636 L 6067,22788"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6066,22839 L 6066,22991"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6066,23042 L 6066,23194"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6066,23245 L 6066,23397"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6065,23448 L 6065,23600"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6065,23651 L 6065,23803"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6065,23854 L 6064,24006"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6064,24057 L 6064,24209"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6064,24260 L 6064,24412"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6064,24463 L 6063,24615"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6063,24666 L 6063,24818"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6063,24869 L 6063,25021"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6063,25072 L 6062,25224"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6062,25275 L 6062,25427"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6062,25478 L 6062,25630"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6062,25681 L 6061,25833"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6061,25884 L 6061,26036"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6061,26087 L 6061,26239"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6061,26290 L 6060,26442"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6060,26493 L 6060,26645"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id5">
+ <rect class="BoundingBox" stroke="none" fill="none" x="7821" y="1245" width="2825" height="893"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 8022,1446 L 10644,1446 10644,2136 8022,2136 8022,1446 8022,1446 Z M 8022,1446 L 8022,1446 Z M 10644,2136 L 10644,2136 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 8022,1446 L 10644,1446 10644,2136 8022,2136 8022,1446 8022,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 8022,1446 L 8022,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 10644,2136 L 10644,2136 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8522" y="1912"><tspan fill="rgb(128,128,128)" stroke="none">Conductor</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 7822,1246 L 10444,1246 10444,1936 7822,1936 7822,1246 7822,1246 Z M 7822,1246 L 7822,1246 Z M 10444,1936 L 10444,1936 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 7822,1246 L 10444,1246 10444,1936 7822,1936 7822,1246 7822,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 7822,1246 L 7822,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10444,1936 L 10444,1936 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8322" y="1712"><tspan fill="rgb(0,0,0)" stroke="none">Conductor</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id6">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9117" y="1947" width="44" height="24709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9159,1948 L 9159,2100"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9159,2151 L 9158,2303"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9158,2354 L 9158,2506"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9158,2557 L 9158,2709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9158,2760 L 9157,2912"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9157,2963 L 9157,3115"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9157,3166 L 9157,3318"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9157,3369 L 9156,3520"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9156,3571 L 9156,3723"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9156,3774 L 9156,3926"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9156,3977 L 9155,4129"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9155,4180 L 9155,4332"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9155,4383 L 9155,4535"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9155,4586 L 9154,4738"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9154,4789 L 9154,4941"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9154,4992 L 9154,5144"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9154,5195 L 9153,5347"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9153,5398 L 9153,5550"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9153,5601 L 9153,5753"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9153,5804 L 9152,5956"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9152,6007 L 9152,6159"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9152,6210 L 9152,6362"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9152,6413 L 9151,6565"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9151,6616 L 9151,6768"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9151,6819 L 9151,6971"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9151,7022 L 9150,7174"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9150,7225 L 9150,7377"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9150,7428 L 9150,7580"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9150,7631 L 9149,7783"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9149,7834 L 9149,7986"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9149,8037 L 9149,8189"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9149,8240 L 9148,8392"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9148,8443 L 9148,8595"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9148,8646 L 9148,8798"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9148,8849 L 9147,9001"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9147,9052 L 9147,9204"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9147,9255 L 9147,9407"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9147,9458 L 9146,9610"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9146,9661 L 9146,9813"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9146,9864 L 9146,10016"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9146,10067 L 9145,10219"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9145,10270 L 9145,10422"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9145,10473 L 9145,10625"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9145,10676 L 9144,10828"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9144,10879 L 9144,11031"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9144,11082 L 9144,11234"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9144,11285 L 9143,11437"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9143,11488 L 9143,11640"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9143,11691 L 9143,11843"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9142,11894 L 9142,12046"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9142,12097 L 9142,12249"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9142,12300 L 9142,12452"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9141,12503 L 9141,12655"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9141,12706 L 9141,12858"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9141,12909 L 9141,13061"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9140,13112 L 9140,13264"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9140,13315 L 9140,13467"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9140,13518 L 9140,13670"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9139,13721 L 9139,13873"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9139,13924 L 9139,14076"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9139,14127 L 9139,14279"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9138,14330 L 9138,14482"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9138,14533 L 9138,14685"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9138,14736 L 9138,14888"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9137,14939 L 9137,15091"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9137,15142 L 9137,15294"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9137,15345 L 9137,15497"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9136,15548 L 9136,15700"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9136,15751 L 9136,15903"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9136,15954 L 9136,16106"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9135,16157 L 9135,16309"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9135,16360 L 9135,16512"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9135,16563 L 9134,16715"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9134,16766 L 9134,16918"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9134,16969 L 9134,17121"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9134,17172 L 9133,17324"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9133,17375 L 9133,17527"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9133,17578 L 9133,17730"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9133,17781 L 9132,17933"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9132,17984 L 9132,18136"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9132,18187 L 9132,18339"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9132,18390 L 9131,18542"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9131,18593 L 9131,18745"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9131,18796 L 9131,18948"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9131,18999 L 9130,19151"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9130,19202 L 9130,19354"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9130,19405 L 9130,19557"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9130,19608 L 9129,19760"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9129,19811 L 9129,19963"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9129,20014 L 9129,20166"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9129,20217 L 9128,20369"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9128,20420 L 9128,20572"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9128,20623 L 9128,20775"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9128,20826 L 9127,20978"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9127,21029 L 9127,21181"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9127,21232 L 9127,21384"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9127,21435 L 9126,21587"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9126,21638 L 9126,21790"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9126,21841 L 9126,21993"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9126,22044 L 9125,22196"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9125,22247 L 9125,22399"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9125,22450 L 9125,22602"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9125,22653 L 9124,22805"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9124,22856 L 9124,23008"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9124,23059 L 9124,23211"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9124,23262 L 9123,23414"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9123,23465 L 9123,23617"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9123,23668 L 9123,23820"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9123,23871 L 9122,24023"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9122,24074 L 9122,24226"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9122,24277 L 9122,24429"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9122,24480 L 9121,24632"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9121,24683 L 9121,24835"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9121,24886 L 9121,25038"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9121,25089 L 9120,25241"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9120,25292 L 9120,25444"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9120,25495 L 9120,25647"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9120,25698 L 9119,25850"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9119,25901 L 9119,26053"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9119,26104 L 9119,26256"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9119,26307 L 9118,26459"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9118,26510 L 9118,26654"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id7">
+ <rect class="BoundingBox" stroke="none" fill="none" x="6069" y="9968" width="3050" height="455"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 6070,10322 L 8831,10322"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 9118,10322 L 8818,10222 8818,10422 9118,10322 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="6273" y="10174"><tspan fill="rgb(0,0,0)" stroke="none">do node deploy</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id8">
+ <rect class="BoundingBox" stroke="none" fill="none" x="1249" y="1239" width="2824" height="894"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 1450,1440 L 4071,1440 4071,2131 1450,2131 1450,1440 1450,1440 Z M 1450,1440 L 1450,1440 Z M 4071,2131 L 4071,2131 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 1450,1440 L 4071,1440 4071,2131 1450,2131 1450,1440 1450,1440 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 1450,1440 L 1450,1440 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 4071,2131 L 4071,2131 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2388" y="1906"><tspan fill="rgb(128,128,128)" stroke="none">User</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 1250,1240 L 3871,1240 3871,1931 1250,1931 1250,1240 1250,1240 Z M 1250,1240 L 1250,1240 Z M 3871,1931 L 3871,1931 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 1250,1240 L 3871,1240 3871,1931 1250,1931 1250,1240 1250,1240 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 1250,1240 L 1250,1240 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 3871,1931 L 3871,1931 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2188" y="1706"><tspan fill="rgb(0,0,0)" stroke="none">User</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id9">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2474" y="2037" width="72" height="24619"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2544,2038 L 2544,2190"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2543,2241 L 2543,2393"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2543,2444 L 2542,2596"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2542,2647 L 2542,2799"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2542,2850 L 2541,3002"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2541,3053 L 2541,3205"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2541,3256 L 2540,3408"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2540,3459 L 2540,3611"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2539,3662 L 2539,3814"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2539,3865 L 2538,4017"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2538,4068 L 2538,4220"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2538,4271 L 2537,4423"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2537,4474 L 2537,4626"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2537,4677 L 2536,4829"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2536,4880 L 2536,5032"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2535,5083 L 2535,5235"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2535,5286 L 2534,5438"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2534,5489 L 2534,5641"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2534,5692 L 2533,5844"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2533,5895 L 2533,6047"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2533,6098 L 2532,6250"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2532,6301 L 2532,6453"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2531,6504 L 2531,6656"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2531,6707 L 2530,6859"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2530,6910 L 2530,7062"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2530,7113 L 2529,7265"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2529,7316 L 2529,7468"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2529,7519 L 2528,7671"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2528,7722 L 2528,7874"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2527,7925 L 2527,8077"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2527,8128 L 2527,8280"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2526,8331 L 2526,8483"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2526,8534 L 2525,8686"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2525,8737 L 2525,8889"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2525,8940 L 2524,9092"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2524,9143 L 2524,9295"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2524,9346 L 2523,9498"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2523,9549 L 2523,9701"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2522,9752 L 2522,9904"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2522,9955 L 2521,10107"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2521,10158 L 2521,10310"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2521,10361 L 2520,10513"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2520,10564 L 2520,10716"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2520,10767 L 2519,10919"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2519,10970 L 2519,11122"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2518,11173 L 2518,11325"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2518,11376 L 2517,11528"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2517,11579 L 2517,11731"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2517,11782 L 2516,11934"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2516,11985 L 2516,12137"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2516,12188 L 2515,12340"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2515,12391 L 2515,12543"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2514,12594 L 2514,12746"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2514,12797 L 2513,12949"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2513,13000 L 2513,13152"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2513,13203 L 2512,13355"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2512,13406 L 2512,13558"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2512,13609 L 2511,13761"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2511,13812 L 2511,13964"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2510,14015 L 2510,14167"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2510,14218 L 2509,14370"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2509,14421 L 2509,14573"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2509,14624 L 2508,14776"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2508,14827 L 2508,14979"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2508,15030 L 2507,15182"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2507,15233 L 2507,15385"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2506,15436 L 2506,15588"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2506,15639 L 2505,15791"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2505,15842 L 2505,15994"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2505,16045 L 2504,16197"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2504,16248 L 2504,16400"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2504,16451 L 2503,16603"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2503,16654 L 2503,16806"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2502,16857 L 2502,17009"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2502,17060 L 2501,17212"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2501,17263 L 2501,17415"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2501,17466 L 2500,17618"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2500,17669 L 2500,17821"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2500,17872 L 2499,18024"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2499,18075 L 2499,18227"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2498,18278 L 2498,18430"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2498,18481 L 2497,18633"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2497,18684 L 2497,18836"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2497,18887 L 2496,19039"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2496,19090 L 2496,19242"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2496,19293 L 2495,19445"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2495,19496 L 2495,19648"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2494,19699 L 2494,19851"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2494,19902 L 2494,20054"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2493,20105 L 2493,20257"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2493,20308 L 2492,20460"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2492,20511 L 2492,20663"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2492,20714 L 2491,20866"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2491,20917 L 2491,21069"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2491,21120 L 2490,21272"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2490,21323 L 2490,21475"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2489,21526 L 2489,21678"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2489,21729 L 2488,21881"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2488,21932 L 2488,22084"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2488,22135 L 2487,22287"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2487,22338 L 2487,22490"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2487,22541 L 2486,22693"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2486,22744 L 2486,22896"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2485,22947 L 2485,23099"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2485,23150 L 2484,23302"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2484,23353 L 2484,23505"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2484,23556 L 2483,23708"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2483,23759 L 2483,23911"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2483,23962 L 2482,24114"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2482,24165 L 2482,24317"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2481,24368 L 2481,24520"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2481,24571 L 2480,24723"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2480,24774 L 2480,24926"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2480,24977 L 2479,25129"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2479,25180 L 2479,25332"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2479,25383 L 2478,25535"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2478,25586 L 2478,25738"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2477,25789 L 2477,25941"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2477,25992 L 2476,26144"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2476,26195 L 2476,26347"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2476,26398 L 2475,26550"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2475,26601 L 2475,26654"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id10">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2581" y="2244" width="3436" height="455"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2582,2597 L 5729,2597"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 6016,2597 L 5716,2497 5716,2697 6016,2597 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="2449"><tspan fill="rgb(0,0,0)" stroke="none">Create ibmc driver node</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id11">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2626" y="2999" width="3436" height="1370"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2627,4267 L 5774,4267"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 6061,4267 L 5761,4167 5761,4367 6061,4267 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2729" y="3204"><tspan fill="rgb(0,0,0)" stroke="none">Set driver_info </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2729" y="3522"><tspan fill="rgb(0,0,0)" stroke="none">(ibmc_address, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2729" y="3840"><tspan fill="rgb(0,0,0)" stroke="none">ibmc_username, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2729" y="4158"><tspan fill="rgb(0,0,0)" stroke="none">ibmc_password, etc)</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id12">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2581" y="4714" width="3436" height="1116"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2582,5728 L 5729,5728"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 6016,5728 L 5716,5628 5716,5828 6016,5728 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="4919"><tspan fill="rgb(0,0,0)" stroke="none">Set instance_info</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="5237"><tspan fill="rgb(0,0,0)" stroke="none">(image_source, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="5555"><tspan fill="rgb(0,0,0)" stroke="none">root_gb, etc.)</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id13">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2581" y="6125" width="3436" height="1167"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2582,7191 L 5729,7191"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 6016,7191 L 5716,7091 5716,7291 6016,7191 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="6331"><tspan fill="rgb(0,0,0)" stroke="none">Validate power, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="6649"><tspan fill="rgb(0,0,0)" stroke="none">management and </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2684" y="6967"><tspan fill="rgb(0,0,0)" stroke="none">vendor interfaces</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id14">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2559" y="7591" width="3436" height="862"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2560,8351 L 5707,8351"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 5994,8351 L 5694,8251 5694,8451 5994,8351 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2662" y="7796"><tspan fill="rgb(0,0,0)" stroke="none">Create bare metal </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2662" y="8114"><tspan fill="rgb(0,0,0)" stroke="none">node network port</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id15">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2514" y="8368" width="3436" height="1116"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2515,9382 L 5662,9382"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 5949,9382 L 5649,9282 5649,9482 5949,9382 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2617" y="8573"><tspan fill="rgb(0,0,0)" stroke="none">Set provision_state, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2617" y="8891"><tspan fill="rgb(0,0,0)" stroke="none">optionally pass </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2617" y="9209"><tspan fill="rgb(0,0,0)" stroke="none">configdrive</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id16">
+ <rect class="BoundingBox" stroke="none" fill="none" x="10779" y="1245" width="2824" height="893"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 10980,1446 L 13601,1446 13601,2136 10980,2136 10980,1446 10980,1446 Z M 10980,1446 L 10980,1446 Z M 13601,2136 L 13601,2136 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 10980,1446 L 13601,1446 13601,2136 10980,2136 10980,1446 10980,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 10980,1446 L 10980,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 13601,2136 L 13601,2136 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="11793" y="1912"><tspan fill="rgb(128,128,128)" stroke="none">DHCP</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 10780,1246 L 13401,1246 13401,1936 10780,1936 10780,1246 10780,1246 Z M 10780,1246 L 10780,1246 Z M 13401,1936 L 13401,1936 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10780,1246 L 13401,1246 13401,1936 10780,1936 10780,1246 10780,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10780,1246 L 10780,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 13401,1936 L 13401,1936 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="11593" y="1712"><tspan fill="rgb(0,0,0)" stroke="none">DHCP</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id17">
+ <rect class="BoundingBox" stroke="none" fill="none" x="12074" y="1947" width="44" height="24709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12116,1948 L 12116,2100"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12116,2151 L 12115,2303"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12115,2354 L 12115,2506"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12115,2557 L 12115,2709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12115,2760 L 12114,2912"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12114,2963 L 12114,3115"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12114,3166 L 12114,3318"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12114,3369 L 12113,3520"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12113,3571 L 12113,3723"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12113,3774 L 12113,3926"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12113,3977 L 12112,4129"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12112,4180 L 12112,4332"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12112,4383 L 12112,4535"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12112,4586 L 12111,4738"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12111,4789 L 12111,4941"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12111,4992 L 12111,5144"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12111,5195 L 12110,5347"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12110,5398 L 12110,5550"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12110,5601 L 12110,5753"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12110,5804 L 12109,5956"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12109,6007 L 12109,6159"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12109,6210 L 12109,6362"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12109,6413 L 12108,6565"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12108,6616 L 12108,6768"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12108,6819 L 12108,6971"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12108,7022 L 12107,7174"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12107,7225 L 12107,7377"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12107,7428 L 12107,7580"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12107,7631 L 12106,7783"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12106,7834 L 12106,7986"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12106,8037 L 12106,8189"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12106,8240 L 12105,8392"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12105,8443 L 12105,8595"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12105,8646 L 12105,8798"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12105,8849 L 12104,9001"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12104,9052 L 12104,9204"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12104,9255 L 12104,9407"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12104,9458 L 12103,9610"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12103,9661 L 12103,9813"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12103,9864 L 12103,10016"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12103,10067 L 12102,10219"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12102,10270 L 12102,10422"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12102,10473 L 12102,10625"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12102,10676 L 12101,10828"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12101,10879 L 12101,11031"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12101,11082 L 12101,11234"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12101,11285 L 12100,11437"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12100,11488 L 12100,11640"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12100,11691 L 12100,11843"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12099,11894 L 12099,12046"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12099,12097 L 12099,12249"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12099,12300 L 12099,12452"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12098,12503 L 12098,12655"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12098,12706 L 12098,12858"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12098,12909 L 12098,13061"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12097,13112 L 12097,13264"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12097,13315 L 12097,13467"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12097,13518 L 12097,13670"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12096,13721 L 12096,13873"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12096,13924 L 12096,14076"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12096,14127 L 12096,14279"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12095,14330 L 12095,14482"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12095,14533 L 12095,14685"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12095,14736 L 12095,14888"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12094,14939 L 12094,15091"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12094,15142 L 12094,15294"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12094,15345 L 12094,15497"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12093,15548 L 12093,15700"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12093,15751 L 12093,15903"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12093,15954 L 12093,16106"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12092,16157 L 12092,16309"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12092,16360 L 12092,16512"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12092,16563 L 12091,16715"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12091,16766 L 12091,16918"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12091,16969 L 12091,17121"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12091,17172 L 12090,17324"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12090,17375 L 12090,17527"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12090,17578 L 12090,17730"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12090,17781 L 12089,17933"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12089,17984 L 12089,18136"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12089,18187 L 12089,18339"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12089,18390 L 12088,18542"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12088,18593 L 12088,18745"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12088,18796 L 12088,18948"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12088,18999 L 12087,19151"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12087,19202 L 12087,19354"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12087,19405 L 12087,19557"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12087,19608 L 12086,19760"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12086,19811 L 12086,19963"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12086,20014 L 12086,20166"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12086,20217 L 12085,20369"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12085,20420 L 12085,20572"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12085,20623 L 12085,20775"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12085,20826 L 12084,20978"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12084,21029 L 12084,21181"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12084,21232 L 12084,21384"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12084,21435 L 12083,21587"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12083,21638 L 12083,21790"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12083,21841 L 12083,21993"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12083,22044 L 12082,22196"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12082,22247 L 12082,22399"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12082,22450 L 12082,22602"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12082,22653 L 12081,22805"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12081,22856 L 12081,23008"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12081,23059 L 12081,23211"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12081,23262 L 12080,23414"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12080,23465 L 12080,23617"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12080,23668 L 12080,23820"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12080,23871 L 12079,24023"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12079,24074 L 12079,24226"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12079,24277 L 12079,24429"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12079,24480 L 12078,24632"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12078,24683 L 12078,24835"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12078,24886 L 12078,25038"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12078,25089 L 12077,25241"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12077,25292 L 12077,25444"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12077,25495 L 12077,25647"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12077,25698 L 12076,25850"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12076,25901 L 12076,26053"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12076,26104 L 12076,26256"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12076,26307 L 12075,26459"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12075,26510 L 12075,26654"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id18">
+ <rect class="BoundingBox" stroke="none" fill="none" x="13682" y="1245" width="2825" height="893"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 13883,1446 L 16505,1446 16505,2136 13883,2136 13883,1446 13883,1446 Z M 13883,1446 L 13883,1446 Z M 16505,2136 L 16505,2136 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 13883,1446 L 16505,1446 16505,2136 13883,2136 13883,1446 13883,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 13883,1446 L 13883,1446 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 16505,2136 L 16505,2136 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="14753" y="1912"><tspan fill="rgb(128,128,128)" stroke="none">TFTP</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 13683,1246 L 16305,1246 16305,1936 13683,1936 13683,1246 13683,1246 Z M 13683,1246 L 13683,1246 Z M 16305,1936 L 16305,1936 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 13683,1246 L 16305,1246 16305,1936 13683,1936 13683,1246 13683,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 13683,1246 L 13683,1246 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 16305,1936 L 16305,1936 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="14553" y="1712"><tspan fill="rgb(0,0,0)" stroke="none">TFTP</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id19">
+ <rect class="BoundingBox" stroke="none" fill="none" x="14978" y="1947" width="44" height="24709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15020,1948 L 15020,2100"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15020,2151 L 15019,2303"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15019,2354 L 15019,2506"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15019,2557 L 15019,2709"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15019,2760 L 15018,2912"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15018,2963 L 15018,3115"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15018,3166 L 15018,3318"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15018,3369 L 15017,3520"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15017,3571 L 15017,3723"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15017,3774 L 15017,3926"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15017,3977 L 15016,4129"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15016,4180 L 15016,4332"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15016,4383 L 15016,4535"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15016,4586 L 15015,4738"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15015,4789 L 15015,4941"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15015,4992 L 15015,5144"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15015,5195 L 15014,5347"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15014,5398 L 15014,5550"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15014,5601 L 15014,5753"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15014,5804 L 15013,5956"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15013,6007 L 15013,6159"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15013,6210 L 15013,6362"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15013,6413 L 15012,6565"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15012,6616 L 15012,6768"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15012,6819 L 15012,6971"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15012,7022 L 15011,7174"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15011,7225 L 15011,7377"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15011,7428 L 15011,7580"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15011,7631 L 15010,7783"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15010,7834 L 15010,7986"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15010,8037 L 15010,8189"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15010,8240 L 15009,8392"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15009,8443 L 15009,8595"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15009,8646 L 15009,8798"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15009,8849 L 15008,9001"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15008,9052 L 15008,9204"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15008,9255 L 15008,9407"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15008,9458 L 15007,9610"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15007,9661 L 15007,9813"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15007,9864 L 15007,10016"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15007,10067 L 15006,10219"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15006,10270 L 15006,10422"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15006,10473 L 15006,10625"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15006,10676 L 15005,10828"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15005,10879 L 15005,11031"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15005,11082 L 15005,11234"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15005,11285 L 15004,11437"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15004,11488 L 15004,11640"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15004,11691 L 15004,11843"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15003,11894 L 15003,12046"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15003,12097 L 15003,12249"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15003,12300 L 15003,12452"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15002,12503 L 15002,12655"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15002,12706 L 15002,12858"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15002,12909 L 15002,13061"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15001,13112 L 15001,13264"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15001,13315 L 15001,13467"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15001,13518 L 15001,13670"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15000,13721 L 15000,13873"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15000,13924 L 15000,14076"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 15000,14127 L 15000,14279"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14999,14330 L 14999,14482"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14999,14533 L 14999,14685"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14999,14736 L 14999,14888"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14998,14939 L 14998,15091"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14998,15142 L 14998,15294"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14998,15345 L 14998,15497"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14997,15548 L 14997,15700"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14997,15751 L 14997,15903"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14997,15954 L 14997,16106"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14996,16157 L 14996,16309"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14996,16360 L 14996,16512"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14996,16563 L 14995,16715"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14995,16766 L 14995,16918"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14995,16969 L 14995,17121"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14995,17172 L 14994,17324"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14994,17375 L 14994,17527"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14994,17578 L 14994,17730"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14994,17781 L 14993,17933"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14993,17984 L 14993,18136"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14993,18187 L 14993,18339"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14993,18390 L 14992,18542"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14992,18593 L 14992,18745"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14992,18796 L 14992,18948"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14992,18999 L 14991,19151"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14991,19202 L 14991,19354"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14991,19405 L 14991,19557"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14991,19608 L 14990,19760"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14990,19811 L 14990,19963"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14990,20014 L 14990,20166"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14990,20217 L 14989,20369"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14989,20420 L 14989,20572"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14989,20623 L 14989,20775"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14989,20826 L 14988,20978"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14988,21029 L 14988,21181"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14988,21232 L 14988,21384"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14988,21435 L 14987,21587"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14987,21638 L 14987,21790"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14987,21841 L 14987,21993"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14987,22044 L 14986,22196"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14986,22247 L 14986,22399"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14986,22450 L 14986,22602"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14986,22653 L 14985,22805"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14985,22856 L 14985,23008"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14985,23059 L 14985,23211"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14985,23262 L 14984,23414"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14984,23465 L 14984,23617"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14984,23668 L 14984,23820"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14984,23871 L 14983,24023"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14983,24074 L 14983,24226"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14983,24277 L 14983,24429"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14983,24480 L 14982,24632"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14982,24683 L 14982,24835"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14982,24886 L 14982,25038"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14982,25089 L 14981,25241"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14981,25292 L 14981,25444"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14981,25495 L 14981,25647"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14981,25698 L 14980,25850"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14980,25901 L 14980,26053"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14980,26104 L 14980,26256"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14980,26307 L 14979,26459"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14979,26510 L 14979,26654"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id20">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9273" y="11583" width="1413" height="3"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9274,11584 L 10684,11584"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id21">
+ <rect class="BoundingBox" stroke="none" fill="none" x="10683" y="11583" width="3" height="434"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10684,11584 L 10684,12015"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id22">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9146" y="11865" width="1563" height="302"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10707,12015 L 9576,12015"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 9146,12015 L 9596,12165 9596,11865 9146,12015 Z"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.TextShape">
+ <g id="id23">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9146" y="10292" width="3358" height="1354"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9248" y="11007"><tspan fill="rgb(0,0,0)" stroke="none">Validate power, </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9248" y="11325"><tspan fill="rgb(0,0,0)" stroke="none">management and </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9248" y="11643"><tspan fill="rgb(0,0,0)" stroke="none">vendor interfaces</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id24">
+ <rect class="BoundingBox" stroke="none" fill="none" x="16854" y="1238" width="2824" height="893"/>
+ <path fill="rgb(128,128,128)" stroke="none" d="M 17055,1439 L 19676,1439 19676,2129 17055,2129 17055,1439 17055,1439 Z M 17055,1439 L 17055,1439 Z M 19676,2129 L 19676,2129 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 17055,1439 L 19676,1439 19676,2129 17055,2129 17055,1439 17055,1439 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 17055,1439 L 17055,1439 Z"/>
+ <path fill="none" stroke="rgb(128,128,128)" d="M 19676,2129 L 19676,2129 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="17946" y="1905"><tspan fill="rgb(128,128,128)" stroke="none">Node</tspan></tspan></tspan></text>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 16855,1239 L 19476,1239 19476,1929 16855,1929 16855,1239 16855,1239 Z M 16855,1239 L 16855,1239 Z M 19476,1929 L 19476,1929 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 16855,1239 L 19476,1239 19476,1929 16855,1929 16855,1239 16855,1239 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 16855,1239 L 16855,1239 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 19476,1929 L 19476,1929 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="17746" y="1705"><tspan fill="rgb(0,0,0)" stroke="none">Node</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id25">
+ <rect class="BoundingBox" stroke="none" fill="none" x="18149" y="1938" width="44" height="24710"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18191,1939 L 18191,2091"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18191,2142 L 18190,2294"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18190,2345 L 18190,2497"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18190,2548 L 18190,2700"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18190,2751 L 18189,2903"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18189,2954 L 18189,3106"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18189,3157 L 18189,3309"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18189,3360 L 18188,3512"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18188,3563 L 18188,3715"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18188,3766 L 18188,3918"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18188,3969 L 18187,4121"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18187,4172 L 18187,4324"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18187,4375 L 18187,4527"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18187,4578 L 18186,4730"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18186,4781 L 18186,4933"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18186,4984 L 18186,5136"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18186,5187 L 18185,5339"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18185,5390 L 18185,5542"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18185,5593 L 18185,5745"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18185,5796 L 18184,5948"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18184,5999 L 18184,6151"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18184,6202 L 18184,6354"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18184,6405 L 18183,6557"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18183,6608 L 18183,6760"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18183,6811 L 18183,6963"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18183,7014 L 18182,7166"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18182,7217 L 18182,7369"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18182,7420 L 18182,7572"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18182,7623 L 18181,7775"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18181,7826 L 18181,7978"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18181,8029 L 18181,8181"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18181,8232 L 18180,8384"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18180,8435 L 18180,8587"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18180,8638 L 18180,8790"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18180,8841 L 18179,8993"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18179,9044 L 18179,9196"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18179,9247 L 18179,9399"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18179,9450 L 18178,9602"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18178,9653 L 18178,9805"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18178,9856 L 18178,10008"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18178,10059 L 18177,10211"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18177,10262 L 18177,10414"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18177,10465 L 18177,10617"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18177,10668 L 18176,10820"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18176,10871 L 18176,11023"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18176,11074 L 18176,11226"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18176,11277 L 18175,11429"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18175,11480 L 18175,11632"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18175,11683 L 18175,11835"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18174,11886 L 18174,12038"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18174,12089 L 18174,12241"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18174,12292 L 18174,12444"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18173,12495 L 18173,12647"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18173,12698 L 18173,12850"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18173,12901 L 18173,13053"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18172,13104 L 18172,13256"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18172,13307 L 18172,13459"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18172,13510 L 18172,13662"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18171,13713 L 18171,13865"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18171,13916 L 18171,14068"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18171,14119 L 18171,14271"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18170,14322 L 18170,14474"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18170,14525 L 18170,14677"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18170,14728 L 18170,14880"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18169,14931 L 18169,15083"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18169,15134 L 18169,15286"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18169,15337 L 18169,15489"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18168,15540 L 18168,15692"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18168,15743 L 18168,15895"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18168,15946 L 18168,16098"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18167,16149 L 18167,16301"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18167,16352 L 18167,16504"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18167,16555 L 18166,16707"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18166,16758 L 18166,16910"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18166,16961 L 18166,17113"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18166,17164 L 18165,17316"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18165,17367 L 18165,17519"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18165,17570 L 18165,17722"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18165,17773 L 18164,17925"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18164,17976 L 18164,18128"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18164,18179 L 18164,18331"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18164,18382 L 18163,18534"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18163,18585 L 18163,18737"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18163,18788 L 18163,18940"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18163,18991 L 18162,19143"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18162,19194 L 18162,19346"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18162,19397 L 18162,19549"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18162,19600 L 18161,19752"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18161,19803 L 18161,19955"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18161,20006 L 18161,20158"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18161,20209 L 18160,20361"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18160,20412 L 18160,20564"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18160,20615 L 18160,20767"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18160,20818 L 18159,20970"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18159,21021 L 18159,21173"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18159,21224 L 18159,21376"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18159,21427 L 18158,21579"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18158,21630 L 18158,21782"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18158,21833 L 18158,21985"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18158,22036 L 18157,22188"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18157,22239 L 18157,22391"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18157,22442 L 18157,22594"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18157,22645 L 18156,22797"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18156,22848 L 18156,23000"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18156,23051 L 18156,23203"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18156,23254 L 18155,23406"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18155,23457 L 18155,23609"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18155,23660 L 18155,23812"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18155,23863 L 18154,24015"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18154,24066 L 18154,24218"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18154,24269 L 18154,24421"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18154,24472 L 18153,24624"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18153,24675 L 18153,24827"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18153,24878 L 18153,25030"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18153,25081 L 18152,25233"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18152,25284 L 18152,25436"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18152,25487 L 18152,25639"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18152,25690 L 18151,25842"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18151,25893 L 18151,26045"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18151,26096 L 18151,26248"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18151,26299 L 18150,26451"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18150,26502 L 18150,26646"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id26">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="14004" width="8897" height="857"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,14710 L 17674,14710"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,14710 L 17654,14560 17654,14860 18104,14710 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="283px" font-weight="400"><tspan class="TextPosition" x="9260" y="14210"><tspan fill="rgb(0,0,0)" stroke="none">Set PXE boot device</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="283px" font-weight="400"><tspan class="TextPosition" x="9260" y="14532"><tspan fill="rgb(0,0,0)" stroke="none">through iBMC</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id27">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="15218" width="8897" height="505"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,15571 L 17674,15571"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,15571 L 17654,15421 17654,15721 18104,15571 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9209" y="15423"><tspan fill="rgb(0,0,0)" stroke="none">REBOOT through iBMC</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id28">
+ <rect class="BoundingBox" stroke="none" fill="none" x="18103" y="19731" width="1540" height="302"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 19641,19882 L 18533,19882"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18103,19882 L 18553,20032 18553,19732 18103,19882 Z"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.TextShape">
+ <g id="id29">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9285" y="11800" width="3358" height="1461"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9285" y="12566"><tspan fill="rgb(0,0,0)" stroke="none">Prepare PXE</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9285" y="12884"><tspan fill="rgb(0,0,0)" stroke="none">environment for</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9285" y="13202"><tspan fill="rgb(0,0,0)" stroke="none">deployment</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id30">
+ <rect class="BoundingBox" stroke="none" fill="none" x="18259" y="18802" width="1445" height="650"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 18260,19450 L 19670,19450"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="18402" y="18997"><tspan fill="rgb(0,0,0)" stroke="none">Run agent </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="18402" y="19315"><tspan fill="rgb(0,0,0)" stroke="none">ramdisk</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id31">
+ <rect class="BoundingBox" stroke="none" fill="none" x="19669" y="19449" width="3" height="434"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 19670,19450 L 19670,19881"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id32">
+ <rect class="BoundingBox" stroke="none" fill="none" x="12174" y="16295" width="5932" height="455"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12461,16649 L 18104,16649"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 12174,16649 L 12474,16749 12474,16549 12174,16649 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="12174" y="16501"><tspan fill="rgb(0,0,0)" stroke="none">Send PXE DHCP request</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id33">
+ <rect class="BoundingBox" stroke="none" fill="none" x="12173" y="16942" width="6088" height="505"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12174,17296 L 17830,17296"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18260,17296 L 17810,17146 17810,17446 18260,17296 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="12174" y="17148"><tspan fill="rgb(0,0,0)" stroke="none">Offer IP to node</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id34">
+ <rect class="BoundingBox" stroke="none" fill="none" x="14982" y="17822" width="3279" height="810"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14983,18481 L 17830,18481"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18260,18481 L 17810,18331 17810,18631 18260,18481 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="15135" y="18028"><tspan fill="rgb(0,0,0)" stroke="none">Send PXE image </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="15135" y="18346"><tspan fill="rgb(0,0,0)" stroke="none">and agent image </tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id35">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9203" y="13482" width="1540" height="302"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10741,13632 L 9633,13632"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 9203,13632 L 9653,13782 9653,13482 9203,13632 Z"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id36">
+ <rect class="BoundingBox" stroke="none" fill="none" x="10769" y="13199" width="3" height="434"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10770,13200 L 10770,13631"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id37">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="13199" width="1564" height="3"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10770,13200 L 9209,13200"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id38">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="20384" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,20636 L 17674,20636"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,20636 L 17654,20486 17654,20786 18104,20636 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="20589"><tspan fill="rgb(0,0,0)" stroke="none">Send IPA a command to expose disks via iSCSI</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id39">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="20849" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,21101 L 17674,21101"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,21101 L 17654,20951 17654,21251 18104,21101 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="21054"><tspan fill="rgb(0,0,0)" stroke="none">iSCSI attach</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id40">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="21314" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,21567 L 17674,21567"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,21567 L 17654,21417 17654,21717 18104,21567 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="21520"><tspan fill="rgb(0,0,0)" stroke="none">Copies user image and configdrive, if presend</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id41">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="21789" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,22042 L 17674,22042"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,22042 L 17654,21892 17654,22192 18104,22042 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="21995"><tspan fill="rgb(0,0,0)" stroke="none">iSCSI detach</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id42">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="22397" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,22649 L 17674,22649"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,22649 L 17654,22499 17654,22799 18104,22649 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="22602"><tspan fill="rgb(0,0,0)" stroke="none">Install boot loader if requested</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id43">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="23004" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,23257 L 17674,23257"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,23257 L 17654,23107 17654,23407 18104,23257 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="23210"><tspan fill="rgb(0,0,0)" stroke="none">Set boot device either to PXE or to disk</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id44">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="23612" width="8897" height="404"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,23864 L 17674,23864"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,23864 L 17654,23714 17654,24014 18104,23864 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="23817"><tspan fill="rgb(0,0,0)" stroke="none">Collect ramdisk logs</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id45">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="24227" width="8897" height="396"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,24472 L 17674,24472"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,24472 L 17654,24322 17654,24622 18104,24472 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="24425"><tspan fill="rgb(0,0,0)" stroke="none">POWER OFF</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id46">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9208" y="24835" width="8897" height="396"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9209,25079 L 17674,25079"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 18104,25079 L 17654,24929 17654,25229 18104,25079 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9260" y="25032"><tspan fill="rgb(0,0,0)" stroke="none">POWER ON</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id47">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9056" y="25334" width="2500" height="610"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 9057,25942 L 11554,25942"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9413" y="25540"><tspan fill="rgb(0,0,0)" stroke="none">Mark node as </tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="9413" y="25858"><tspan fill="rgb(0,0,0)" stroke="none">ACTIVE</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id48">
+ <rect class="BoundingBox" stroke="none" fill="none" x="11553" y="25941" width="3" height="596"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11554,25942 L 11554,26535"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id49">
+ <rect class="BoundingBox" stroke="none" fill="none" x="9057" y="26385" width="2499" height="302"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11554,26535 L 9487,26535"/>
+ <path fill="rgb(0,0,0)" stroke="none" d="M 9057,26535 L 9507,26685 9507,26385 9057,26535 Z"/>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id50">
+ <rect class="BoundingBox" stroke="none" fill="none" x="11920" y="13952" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 12111,13953 C 12219,13953 12302,14035 12302,14143 12302,14251 12219,14334 12111,14334 12003,14334 11921,14251 11921,14143 11921,14035 12003,13953 12111,13953 Z M 11921,13953 L 11921,13953 Z M 12303,14335 L 12303,14335 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12111,13953 C 12219,13953 12302,14035 12302,14143 12302,14251 12219,14334 12111,14334 12003,14334 11921,14251 11921,14143 11921,14035 12003,13953 12111,13953 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11921,13953 L 11921,13953 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12303,14335 L 12303,14335 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="12033" y="14268"><tspan fill="rgb(0,0,0)" stroke="none">1</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id51">
+ <rect class="BoundingBox" stroke="none" fill="none" x="12320" y="15052" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 12511,15053 C 12619,15053 12702,15135 12702,15243 12702,15351 12619,15434 12511,15434 12403,15434 12321,15351 12321,15243 12321,15135 12403,15053 12511,15053 Z M 12321,15053 L 12321,15053 Z M 12703,15435 L 12703,15435 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12511,15053 C 12619,15053 12702,15135 12702,15243 12702,15351 12619,15434 12511,15434 12403,15434 12321,15351 12321,15243 12321,15135 12403,15053 12511,15053 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12321,15053 L 12321,15053 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 12703,15435 L 12703,15435 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="12433" y="15368"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id52">
+ <rect class="BoundingBox" stroke="none" fill="none" x="14320" y="22852" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 14511,22853 C 14619,22853 14702,22935 14702,23043 14702,23151 14619,23234 14511,23234 14403,23234 14321,23151 14321,23043 14321,22935 14403,22853 14511,22853 Z M 14321,22853 L 14321,22853 Z M 14703,23235 L 14703,23235 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14511,22853 C 14619,22853 14702,22935 14702,23043 14702,23151 14619,23234 14511,23234 14403,23234 14321,23151 14321,23043 14321,22935 14403,22853 14511,22853 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14321,22853 L 14321,22853 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 14703,23235 L 14703,23235 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="14433" y="23168"><tspan fill="rgb(0,0,0)" stroke="none">1</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id53">
+ <rect class="BoundingBox" stroke="none" fill="none" x="11120" y="24052" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 11311,24053 C 11419,24053 11502,24135 11502,24243 11502,24351 11419,24434 11311,24434 11203,24434 11121,24351 11121,24243 11121,24135 11203,24053 11311,24053 Z M 11121,24053 L 11121,24053 Z M 11503,24435 L 11503,24435 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11311,24053 C 11419,24053 11502,24135 11502,24243 11502,24351 11419,24434 11311,24434 11203,24434 11121,24351 11121,24243 11121,24135 11203,24053 11311,24053 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11121,24053 L 11121,24053 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11503,24435 L 11503,24435 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="11233" y="24368"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id54">
+ <rect class="BoundingBox" stroke="none" fill="none" x="10920" y="24652" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 11111,24653 C 11219,24653 11302,24735 11302,24843 11302,24951 11219,25034 11111,25034 11003,25034 10921,24951 10921,24843 10921,24735 11003,24653 11111,24653 Z M 10921,24653 L 10921,24653 Z M 11303,25035 L 11303,25035 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11111,24653 C 11219,24653 11302,24735 11302,24843 11302,24951 11219,25034 11111,25034 11003,25034 10921,24951 10921,24843 10921,24735 11003,24653 11111,24653 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 10921,24653 L 10921,24653 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 11303,25035 L 11303,25035 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="11033" y="24968"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id55">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2320" y="27952" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 2511,27953 C 2619,27953 2702,28035 2702,28143 2702,28251 2619,28334 2511,28334 2403,28334 2321,28251 2321,28143 2321,28035 2403,27953 2511,27953 Z M 2321,27953 L 2321,27953 Z M 2703,28335 L 2703,28335 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2511,27953 C 2619,27953 2702,28035 2702,28143 2702,28251 2619,28334 2511,28334 2403,28334 2321,28251 2321,28143 2321,28035 2403,27953 2511,27953 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2321,27953 L 2321,27953 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2703,28335 L 2703,28335 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2433" y="28268"><tspan fill="rgb(0,0,0)" stroke="none">2</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.CustomShape">
+ <g id="id56">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2320" y="27320" width="385" height="385"/>
+ <path fill="rgb(255,255,255)" stroke="none" d="M 2511,27321 C 2619,27321 2702,27403 2702,27511 2702,27619 2619,27702 2511,27702 2403,27702 2321,27619 2321,27511 2321,27403 2403,27321 2511,27321 Z M 2321,27321 L 2321,27321 Z M 2703,27703 L 2703,27703 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2511,27321 C 2619,27321 2702,27403 2702,27511 2702,27619 2619,27702 2511,27702 2403,27702 2321,27619 2321,27511 2321,27403 2403,27321 2511,27321 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2321,27321 L 2321,27321 Z"/>
+ <path fill="none" stroke="rgb(0,0,0)" d="M 2703,27703 L 2703,27703 Z"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2433" y="27636"><tspan fill="rgb(0,0,0)" stroke="none">1</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id57">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2769" y="27408" width="3588" height="305"/>
+ <path fill="none" stroke="rgb(255,255,255)" d="M 2778,27711 L 6334,27711"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2778" y="27613"><tspan fill="rgb(0,0,0)" stroke="none">IBMC management interface</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ <g class="com.sun.star.drawing.LineShape">
+ <g id="id58">
+ <rect class="BoundingBox" stroke="none" fill="none" x="2776" y="28061" width="3567" height="305"/>
+ <path fill="none" stroke="rgb(255,255,255)" d="M 2785,28364 L 6341,28364"/>
+ <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2785" y="28266"><tspan fill="rgb(0,0,0)" stroke="none">IBMC power interface</tspan></tspan></tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/driver-requirements.txt b/driver-requirements.txt
index c49f74e1d..eabafe748 100644
--- a/driver-requirements.txt
+++ b/driver-requirements.txt
@@ -20,3 +20,6 @@ sushy>=1.6.0
# Ansible-deploy interface
ansible>=2.4
+
+# HUAWEI iBMC hardware type uses the python-ibmcclient library
+python-ibmcclient>=0.1.0
diff --git a/ironic/common/exception.py b/ironic/common/exception.py
index 3ee9d8c41..96be2b0fa 100644
--- a/ironic/common/exception.py
+++ b/ironic/common/exception.py
@@ -825,3 +825,11 @@ class DeployTemplateNotFound(NotFound):
class InvalidDeployTemplate(Invalid):
_msg_fmt = _("Deploy template invalid: %(err)s.")
+
+
+class IBMCError(DriverOperationError):
+ _msg_fmt = _("IBMC exception occurred on node %(node)s. Error: %(error)s")
+
+
+class IBMCConnectionError(IBMCError):
+ _msg_fmt = _("IBMC connection failed for node %(node)s: %(error)s")
diff --git a/ironic/conf/__init__.py b/ironic/conf/__init__.py
index a2d4ae4b6..01d7042b3 100644
--- a/ironic/conf/__init__.py
+++ b/ironic/conf/__init__.py
@@ -30,6 +30,7 @@ from ironic.conf import dhcp
from ironic.conf import drac
from ironic.conf import glance
from ironic.conf import healthcheck
+from ironic.conf import ibmc
from ironic.conf import ilo
from ironic.conf import inspector
from ironic.conf import ipmi
@@ -63,6 +64,7 @@ drac.register_opts(CONF)
dhcp.register_opts(CONF)
glance.register_opts(CONF)
healthcheck.register_opts(CONF)
+ibmc.register_opts(CONF)
ilo.register_opts(CONF)
inspector.register_opts(CONF)
ipmi.register_opts(CONF)
diff --git a/ironic/conf/ibmc.py b/ironic/conf/ibmc.py
new file mode 100644
index 000000000..82c5eaac7
--- /dev/null
+++ b/ironic/conf/ibmc.py
@@ -0,0 +1,35 @@
+#
+# 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.
+
+# Version 1.0.0
+
+from oslo_config import cfg
+
+from ironic.common.i18n import _
+
+opts = [
+ cfg.IntOpt('connection_attempts',
+ min=1,
+ default=5,
+ help=_('Maximum number of attempts to try to connect '
+ 'to iBMC')),
+ cfg.IntOpt('connection_retry_interval',
+ min=1,
+ default=4,
+ help=_('Number of seconds to wait between attempts to '
+ 'connect to iBMC'))
+]
+
+
+def register_opts(conf):
+ conf.register_opts(opts, group='ibmc')
diff --git a/ironic/drivers/ibmc.py b/ironic/drivers/ibmc.py
new file mode 100644
index 000000000..a9d659ecf
--- /dev/null
+++ b/ironic/drivers/ibmc.py
@@ -0,0 +1,40 @@
+#
+# 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.
+"""
+iBMC Driver for managing HUAWEI Huawei 2288H V5, CH121 V5 series servers.
+"""
+
+from ironic.drivers import generic
+from ironic.drivers.modules.ibmc import management as ibmc_mgmt
+from ironic.drivers.modules.ibmc import power as ibmc_power
+from ironic.drivers.modules.ibmc import vendor as ibmc_vendor
+from ironic.drivers.modules import noop
+
+
+class IBMCHardware(generic.GenericHardware):
+ """Huawei iBMC hardware type."""
+
+ @property
+ def supported_management_interfaces(self):
+ """List of supported management interfaces."""
+ return [ibmc_mgmt.IBMCManagement]
+
+ @property
+ def supported_power_interfaces(self):
+ """List of supported power interfaces."""
+ return [ibmc_power.IBMCPower]
+
+ @property
+ def supported_vendor_interfaces(self):
+ """List of supported vendor interfaces."""
+ return [ibmc_vendor.IBMCVendor, noop.NoVendor]
diff --git a/ironic/drivers/modules/ibmc/__init__.py b/ironic/drivers/modules/ibmc/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/__init__.py
diff --git a/ironic/drivers/modules/ibmc/management.py b/ironic/drivers/modules/ibmc/management.py
new file mode 100644
index 000000000..672501a7b
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/management.py
@@ -0,0 +1,237 @@
+# Copyright 2019 HUAWEI, Inc. All Rights Reserved.
+# Copyright 2017 Red Hat, Inc. All Rights Reserved.
+#
+# 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.
+"""
+iBMC Management Interface
+"""
+
+from oslo_log import log
+from oslo_utils import importutils
+
+from ironic.common import exception
+from ironic.common.i18n import _
+from ironic.conductor import task_manager
+from ironic.drivers import base
+from ironic.drivers.modules.ibmc import mappings
+from ironic.drivers.modules.ibmc import utils
+
+constants = importutils.try_import('ibmc_client.constants')
+ibmc_client = importutils.try_import('ibmc_client')
+
+LOG = log.getLogger(__name__)
+
+
+class IBMCManagement(base.ManagementInterface):
+
+ def __init__(self):
+ """Initialize the iBMC management interface
+
+ :raises: DriverLoadError if the driver can't be loaded due to
+ missing dependencies
+ """
+ super(IBMCManagement, self).__init__()
+ if not ibmc_client:
+ raise exception.DriverLoadError(
+ driver='ibmc',
+ reason=_('Unable to import the python-ibmcclient library'))
+
+ def get_properties(self):
+ """Return the properties of the interface.
+
+ :returns: dictionary of <property name>:<property description> entries.
+ """
+ return utils.COMMON_PROPERTIES.copy()
+
+ def validate(self, task):
+ """Validates the driver information needed by the iBMC driver.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ """
+ utils.parse_driver_info(task.node)
+
+ @utils.handle_ibmc_exception('get iBMC supported boot devices')
+ def get_supported_boot_devices(self, task):
+ """Get a list of the supported boot devices.
+
+ :param task: a task from TaskManager.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ :returns: A list with the supported boot devices defined
+ in :mod:`ironic.common.boot_devices`.
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ boot_source_override = system.boot_source_override
+ return list(map(mappings.GET_BOOT_DEVICE_MAP.get,
+ boot_source_override.supported_boot_devices))
+
+ @task_manager.require_exclusive_lock
+ @utils.handle_ibmc_exception('set iBMC boot device')
+ def set_boot_device(self, task, device, persistent=False):
+ """Set the boot device for a node.
+
+ :param task: A task from TaskManager.
+ :param device: The boot device, one of
+ :mod:`ironic.common.boot_device`.
+ :param persistent: Boolean value. True if the boot device will
+ persist to all future boots, False if not.
+ Default: False.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ boot_device = mappings.SET_BOOT_DEVICE_MAP[device]
+ enabled = mappings.SET_BOOT_DEVICE_PERSISTENT_MAP[persistent]
+ conn.system.set_boot_source(boot_device, enabled=enabled)
+
+ @utils.handle_ibmc_exception('get iBMC boot device')
+ def get_boot_device(self, task):
+ """Get the current boot device for a node.
+
+ :param task: A task from TaskManager.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ :returns: a dictionary containing:
+
+ :boot_device:
+ the boot device, one of :mod:`ironic.common.boot_devices` or
+ None if it is unknown.
+ :persistent:
+ Boolean value or None, True if the boot device persists,
+ False otherwise. None if it's disabled.
+
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ boot_source_override = system.boot_source_override
+ boot_device = boot_source_override.target
+ enabled = boot_source_override.enabled
+ return {
+ 'boot_device': mappings.GET_BOOT_DEVICE_MAP.get(boot_device),
+ 'persistent':
+ mappings.GET_BOOT_DEVICE_PERSISTENT_MAP.get(enabled)
+ }
+
+ def get_supported_boot_modes(self, task):
+ """Get a list of the supported boot modes.
+
+ :param task: A task from TaskManager.
+ :returns: A list with the supported boot modes defined
+ in :mod:`ironic.common.boot_modes`. If boot
+ mode support can't be determined, empty list
+ is returned.
+ """
+ return list(mappings.SET_BOOT_MODE_MAP)
+
+ @task_manager.require_exclusive_lock
+ @utils.handle_ibmc_exception('set iBMC boot mode')
+ def set_boot_mode(self, task, mode):
+ """Set the boot mode for a node.
+
+ Set the boot mode to use on next reboot of the node.
+
+ :param task: A task from TaskManager.
+ :param mode: The boot mode, one of
+ :mod:`ironic.common.boot_modes`.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ boot_source_override = system.boot_source_override
+ boot_device = boot_source_override.target
+ boot_override = boot_source_override.enabled
+
+ # Copied from redfish driver
+ # TODO(Qianbiao.NG) what if boot device is "NONE"?
+ if not boot_device:
+ error_msg = (_('Cannot change boot mode on node %(node)s '
+ 'because its boot device is not set.') %
+ {'node': task.node.uuid})
+ LOG.error(error_msg)
+ raise exception.IBMCError(error_msg)
+
+ # TODO(Qianbiao.NG) what if boot override is "disabled"?
+ if not boot_override:
+ i18n = _('Cannot change boot mode on node %(node)s '
+ 'because its boot source override is not set.')
+ error_msg = i18n % {'node': task.node.uuid}
+ LOG.error(error_msg)
+ raise exception.IBMCError(error_msg)
+
+ boot_mode = mappings.SET_BOOT_MODE_MAP[mode]
+ conn.system.set_boot_source(boot_device,
+ enabled=boot_override,
+ mode=boot_mode)
+
+ @utils.handle_ibmc_exception('get iBMC boot mode')
+ def get_boot_mode(self, task):
+ """Get the current boot mode for a node.
+
+ Provides the current boot mode of the node.
+
+ :param task: A task from TaskManager.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ :returns: The boot mode, one of :mod:`ironic.common.boot_mode` or
+ None if it is unknown.
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ boot_source_override = system.boot_source_override
+ boot_mode = boot_source_override.mode
+ return mappings.GET_BOOT_MODE_MAP.get(boot_mode)
+
+ def get_sensors_data(self, task):
+ """Get sensors data.
+
+ Not implemented for this driver.
+
+ :raises: NotImplementedError
+ """
+ raise NotImplementedError()
+
+ @task_manager.require_exclusive_lock
+ @utils.handle_ibmc_exception('inject iBMC NMI')
+ def inject_nmi(self, task):
+ """Inject NMI, Non Maskable Interrupt.
+
+ Inject NMI (Non Maskable Interrupt) for a node immediately.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ conn.system.reset(constants.RESET_NMI)
diff --git a/ironic/drivers/modules/ibmc/mappings.py b/ironic/drivers/modules/ibmc/mappings.py
new file mode 100644
index 000000000..e303a72ea
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/mappings.py
@@ -0,0 +1,70 @@
+#
+# 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.
+"""
+iBMC and Ironic constants mapping
+"""
+
+from oslo_utils import importutils
+
+from ironic.common import boot_devices
+from ironic.common import boot_modes
+from ironic.common import states
+from ironic.drivers.modules.ibmc import utils
+
+constants = importutils.try_import('ibmc_client.constants')
+
+if constants:
+ # Set power state mapping
+ SET_POWER_STATE_MAP = {
+ states.POWER_ON: constants.RESET_ON,
+ states.POWER_OFF: constants.RESET_FORCE_OFF,
+ states.REBOOT: constants.RESET_FORCE_RESTART,
+ states.SOFT_REBOOT: constants.RESET_FORCE_POWER_CYCLE,
+ states.SOFT_POWER_OFF: constants.RESET_GRACEFUL_SHUTDOWN,
+ }
+
+ # Get power state mapping
+ GET_POWER_STATE_MAP = {
+ constants.SYSTEM_POWER_STATE_ON: states.POWER_ON,
+ constants.SYSTEM_POWER_STATE_OFF: states.POWER_OFF,
+ }
+
+ # Boot device mapping
+ GET_BOOT_DEVICE_MAP = {
+ constants.BOOT_SOURCE_TARGET_NONE: 'none',
+ constants.BOOT_SOURCE_TARGET_PXE: boot_devices.PXE,
+ constants.BOOT_SOURCE_TARGET_FLOPPY: 'floppy',
+ constants.BOOT_SOURCE_TARGET_CD: boot_devices.CDROM,
+ constants.BOOT_SOURCE_TARGET_HDD: boot_devices.DISK,
+ constants.BOOT_SOURCE_TARGET_BIOS_SETUP: boot_devices.BIOS,
+ }
+
+ SET_BOOT_DEVICE_MAP = utils.revert_dictionary(GET_BOOT_DEVICE_MAP)
+
+ # Boot mode mapping
+ GET_BOOT_MODE_MAP = {
+ constants.BOOT_SOURCE_MODE_BIOS: boot_modes.LEGACY_BIOS,
+ constants.BOOT_SOURCE_MODE_UEFI: boot_modes.UEFI,
+ }
+
+ SET_BOOT_MODE_MAP = utils.revert_dictionary(GET_BOOT_MODE_MAP)
+
+ # Boot device persistent mapping
+ GET_BOOT_DEVICE_PERSISTENT_MAP = {
+ constants.BOOT_SOURCE_ENABLED_ONCE: False,
+ constants.BOOT_SOURCE_ENABLED_CONTINUOUS: True,
+ constants.BOOT_SOURCE_ENABLED_DISABLED: None,
+ }
+
+ SET_BOOT_DEVICE_PERSISTENT_MAP = utils.revert_dictionary(
+ GET_BOOT_DEVICE_PERSISTENT_MAP)
diff --git a/ironic/drivers/modules/ibmc/power.py b/ironic/drivers/modules/ibmc/power.py
new file mode 100644
index 000000000..6bb15ee22
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/power.py
@@ -0,0 +1,145 @@
+#
+# 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.
+"""
+iBMC Power Interface
+"""
+
+from oslo_log import log
+from oslo_utils import importutils
+
+from ironic.common import exception
+from ironic.common.i18n import _
+from ironic.common import states
+from ironic.conductor import task_manager
+from ironic.conductor import utils as cond_utils
+from ironic.drivers import base
+from ironic.drivers.modules.ibmc import mappings
+from ironic.drivers.modules.ibmc import utils
+
+constants = importutils.try_import('ibmc_client.constants')
+ibmc_client = importutils.try_import('ibmc_client')
+
+LOG = log.getLogger(__name__)
+
+EXPECT_POWER_STATE_MAP = {
+ states.REBOOT: states.POWER_ON,
+ states.SOFT_REBOOT: states.POWER_ON,
+ states.SOFT_POWER_OFF: states.POWER_OFF,
+}
+
+
+class IBMCPower(base.PowerInterface):
+
+ def __init__(self):
+ """Initialize the iBMC power interface.
+
+ :raises: DriverLoadError if the driver can't be loaded due to
+ missing dependencies
+ """
+ super(IBMCPower, self).__init__()
+ if not ibmc_client:
+ raise exception.DriverLoadError(
+ driver='ibmc',
+ reason=_('Unable to import the python-ibmcclient library'))
+
+ def get_properties(self):
+ """Return the properties of the interface.
+
+ :returns: dictionary of <property name>:<property description> entries.
+ """
+ return utils.COMMON_PROPERTIES.copy()
+
+ def validate(self, task):
+ """Validates the driver information needed by the iBMC driver.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ """
+ utils.parse_driver_info(task.node)
+
+ @utils.handle_ibmc_exception('get iBMC power state')
+ def get_power_state(self, task):
+ """Get the current power state of the task's node.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :returns: A power state. One of :mod:`ironic.common.states`.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ return mappings.GET_POWER_STATE_MAP.get(system.power_state)
+
+ @task_manager.require_exclusive_lock
+ @utils.handle_ibmc_exception('set iBMC power state')
+ def set_power_state(self, task, power_state, timeout=None):
+ """Set the power state of the task's node.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :param power_state: Any power state from :mod:`ironic.common.states`.
+ :param timeout: Time to wait for the node to reach the requested state.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue if a required parameter is missing.
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ reset_type = mappings.SET_POWER_STATE_MAP.get(power_state)
+ conn.system.reset(reset_type)
+
+ target_state = EXPECT_POWER_STATE_MAP.get(power_state, power_state)
+ cond_utils.node_wait_for_power_state(task, target_state,
+ timeout=timeout)
+
+ @task_manager.require_exclusive_lock
+ @utils.handle_ibmc_exception('reboot iBMC')
+ def reboot(self, task, timeout=None):
+ """Perform a hard reboot of the task's node.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :param timeout: Time to wait for the node to become powered on.
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue if a required parameter is missing.
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ """
+ ibmc = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**ibmc) as conn:
+ system = conn.system.get()
+ current_power_state = (
+ mappings.GET_POWER_STATE_MAP.get(system.power_state)
+ )
+ if current_power_state == states.POWER_ON:
+ conn.system.reset(
+ mappings.SET_POWER_STATE_MAP.get(states.REBOOT))
+ else:
+ conn.system.reset(
+ mappings.SET_POWER_STATE_MAP.get(states.POWER_ON))
+
+ cond_utils.node_wait_for_power_state(task, states.POWER_ON,
+ timeout=timeout)
+
+ def get_supported_power_states(self, task):
+ """Get a list of the supported power states.
+
+ :param task: A TaskManager instance containing the node to act on.
+ Not used by this driver at the moment.
+ :returns: A list with the supported power states defined
+ in :mod:`ironic.common.states`.
+ """
+ return list(mappings.SET_POWER_STATE_MAP)
diff --git a/ironic/drivers/modules/ibmc/utils.py b/ironic/drivers/modules/ibmc/utils.py
new file mode 100644
index 000000000..d06a88b85
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/utils.py
@@ -0,0 +1,177 @@
+#
+# 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.
+"""
+iBMC Driver common utils
+"""
+
+import os
+
+from oslo_log import log
+from oslo_utils import importutils
+from oslo_utils import netutils
+from oslo_utils import strutils
+import retrying
+import six
+
+from ironic.common import exception
+from ironic.common.i18n import _
+from ironic.conductor import task_manager
+from ironic.conf import CONF
+
+ibmc_client = importutils.try_import('ibmcclient')
+ibmc_error = importutils.try_import('ibmc_client.exceptions')
+
+LOG = log.getLogger(__name__)
+
+REQUIRED_PROPERTIES = {
+ 'ibmc_address': _('The URL address to the iBMC controller. It must '
+ 'include the authority portion of the URL. '
+ 'If the scheme is missing, https is assumed. '
+ 'For example: https://mgmt.vendor.com. Required.'),
+ 'ibmc_username': _('User account with admin/server-profile access '
+ 'privilege. Required.'),
+ 'ibmc_password': _('User account password. Required.'),
+}
+
+OPTIONAL_PROPERTIES = {
+ 'ibmc_verify_ca': _('Either a Boolean value, a path to a CA_BUNDLE '
+ 'file or directory with certificates of trusted '
+ 'CAs. If set to True the driver will verify the '
+ 'host certificates; if False the driver will '
+ 'ignore verifying the SSL certificate. If it\'s '
+ 'a path the driver will use the specified '
+ 'certificate or one of the certificates in the '
+ 'directory. Defaults to True. Optional.'),
+}
+
+COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
+COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES)
+
+
+def parse_driver_info(node):
+ """Parse the information required for Ironic to connect to iBMC.
+
+ :param node: an Ironic node object
+ :returns: dictionary of parameters
+ :raises: InvalidParameterValue on malformed parameter(s)
+ :raises: MissingParameterValue on missing parameter(s)
+ """
+ driver_info = node.driver_info or {}
+ missing_info = [key for key in REQUIRED_PROPERTIES
+ if not driver_info.get(key)]
+ if missing_info:
+ raise exception.MissingParameterValue(_(
+ 'Missing the following iBMC properties in node '
+ '%(node)s driver_info: %(info)s') % {'node': node.uuid,
+ 'info': missing_info})
+
+ # Validate the iBMC address
+ address = driver_info['ibmc_address']
+ parsed = netutils.urlsplit(address)
+ if parsed.scheme == '':
+ address = 'https://%s' % address
+ parsed = netutils.urlsplit(address)
+
+ if parsed.netloc == '':
+ raise exception.InvalidParameterValue(
+ _('Invalid iBMC address %(address)s set in '
+ 'driver_info/ibmc_address on node %(node)s') %
+ {'address': address, 'node': node.uuid})
+
+ # Check if verify_ca is a Boolean or a file/directory in the file-system
+ verify_ca = driver_info.get('ibmc_verify_ca', True)
+ if isinstance(verify_ca, six.string_types):
+ if os.path.isdir(verify_ca) or os.path.isfile(verify_ca):
+ pass
+ else:
+ try:
+ verify_ca = strutils.bool_from_string(verify_ca, strict=True)
+ except ValueError:
+ raise exception.InvalidParameterValue(
+ _('Invalid value type set in driver_info/'
+ 'ibmc_verify_ca on node %(node)s. '
+ 'The value should be a Boolean or the path '
+ 'to a file/directory, not "%(value)s"'
+ ) % {'value': verify_ca, 'node': node.uuid})
+ elif isinstance(verify_ca, bool):
+ # If it's a boolean it's grand, we don't need to do anything
+ pass
+ else:
+ raise exception.InvalidParameterValue(
+ _('Invalid value type set in driver_info/ibmc_verify_ca '
+ 'on node %(node)s. The value should be a Boolean or the path '
+ 'to a file/directory, not "%(value)s"') % {'value': verify_ca,
+ 'node': node.uuid})
+ return {'address': address,
+ 'username': driver_info.get('ibmc_username'),
+ 'password': driver_info.get('ibmc_password'),
+ 'verify_ca': verify_ca}
+
+
+def revert_dictionary(d):
+ return {v: k for k, v in d.items()}
+
+
+def handle_ibmc_exception(action):
+ """Decorator to handle iBMC client exception.
+
+ Decorated functions must take a :class:`TaskManager` as the first
+ parameter.
+ """
+
+ def decorator(f):
+
+ def should_retry(e):
+ connect_error = isinstance(e, exception.IBMCConnectionError)
+ if connect_error:
+ LOG.info(_('Failed to connect to iBMC, will retry now. '
+ 'Max retry times is %(retry_times)d.'),
+ {'retry_times': CONF.ibmc.connection_attempts})
+ return connect_error
+
+ @retrying.retry(
+ retry_on_exception=should_retry,
+ stop_max_attempt_number=CONF.ibmc.connection_attempts,
+ wait_fixed=CONF.ibmc.connection_retry_interval * 1000)
+ @six.wraps(f)
+ def wrapper(*args, **kwargs):
+ # NOTE(dtantsur): this code could be written simpler, but then unit
+ # testing decorated functions is pretty hard, as we usually pass a
+ # Mock object instead of TaskManager there.
+ if len(args) > 1:
+ is_task_mgr = isinstance(args[1], task_manager.TaskManager)
+ task = args[1] if is_task_mgr else args[0]
+ else:
+ task = args[0]
+
+ node = task.node
+
+ try:
+ return f(*args, **kwargs)
+ except ibmc_error.ConnectionError as e:
+ error = (_('Failed to connect to iBMC for node %(node)s, '
+ 'Error: %(error)s')
+ % {'node': node.uuid, 'error': e})
+ LOG.error(error)
+ raise exception.IBMCConnectionError(node=node.uuid,
+ error=error)
+ except ibmc_error.IBMCClientError as e:
+ error = (_('Failed to %(action)s for node %(node)s, '
+ 'Error %(error)s')
+ % {'node': node.uuid, 'action': action, 'error': e})
+ LOG.error(error)
+ raise exception.IBMCError(node=node.uuid, error=error)
+
+ return wrapper
+
+ return decorator
diff --git a/ironic/drivers/modules/ibmc/vendor.py b/ironic/drivers/modules/ibmc/vendor.py
new file mode 100644
index 000000000..24d497cf7
--- /dev/null
+++ b/ironic/drivers/modules/ibmc/vendor.py
@@ -0,0 +1,87 @@
+#
+# 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.
+"""
+iBMC Vendor Interface
+"""
+
+from oslo_log import log
+from oslo_utils import importutils
+
+from ironic.common import exception
+from ironic.common.i18n import _
+from ironic.drivers import base
+from ironic.drivers.modules.ibmc import utils
+
+ibmc_client = importutils.try_import('ibmc_client')
+
+LOG = log.getLogger(__name__)
+
+
+class IBMCVendor(base.VendorInterface):
+
+ def __init__(self):
+ """Initialize the iBMC vendor interface.
+
+ :raises: DriverLoadError if the driver can't be loaded due to
+ missing dependencies
+ """
+ super(IBMCVendor, self).__init__()
+ if not ibmc_client:
+ raise exception.DriverLoadError(
+ driver='ibmc',
+ reason=_('Unable to import the python-ibmcclient library'))
+
+ def validate(self, task, method=None, **kwargs):
+ """Validate vendor-specific actions.
+
+ If invalid, raises an exception; otherwise returns None.
+
+ :param task: A task from TaskManager.
+ :param method: Method to be validated
+ :param kwargs: Info for action.
+ :raises: UnsupportedDriverExtension if 'method' can not be mapped to
+ the supported interfaces.
+ :raises: InvalidParameterValue if kwargs does not contain 'method'.
+ :raises: MissingParameterValue
+ """
+ utils.parse_driver_info(task.node)
+
+ def get_properties(self):
+ """Return the properties of the interface.
+
+ :returns: dictionary of <property name>:<property description> entries.
+ """
+ return utils.COMMON_PROPERTIES.copy()
+
+ @base.passthru(['GET'], async_call=False,
+ description=_('Returns a dictionary, '
+ 'containing node boot up sequence, '
+ 'in ascending order'))
+ @utils.handle_ibmc_exception('get iBMC boot up sequence')
+ def boot_up_seq(self, task, **kwargs):
+ """List boot type order of the node.
+
+ :param task: A TaskManager instance containing the node to act on.
+ :param kwargs: Not used.
+ :raises: InvalidParameterValue if kwargs does not contain 'method'.
+ :raises: MissingParameterValue
+ :raises: IBMCConnectionError when it fails to connect to iBMC
+ :raises: IBMCError when iBMC responses an error information
+ :returns: A dictionary, containing node boot up sequence,
+ in ascending order.
+ """
+ driver_info = utils.parse_driver_info(task.node)
+ with ibmc_client.connect(**driver_info) as conn:
+ system = conn.system.get()
+ boot_sequence = system.boot_sequence
+ return {'boot_up_sequence': boot_sequence}
diff --git a/ironic/tests/unit/db/utils.py b/ironic/tests/unit/db/utils.py
index 2d44efa1a..4c7354ef2 100644
--- a/ironic/tests/unit/db/utils.py
+++ b/ironic/tests/unit/db/utils.py
@@ -671,3 +671,12 @@ def create_test_deploy_template(**kw):
if 'id' not in kw_step:
del template_step['id']
return dbapi.create_deploy_template(template)
+
+
+def get_test_ibmc_info():
+ return {
+ "ibmc_address": "https://example.com",
+ "ibmc_username": "username",
+ "ibmc_password": "password",
+ "verify_ca": False,
+ }
diff --git a/ironic/tests/unit/drivers/modules/ibmc/__init__.py b/ironic/tests/unit/drivers/modules/ibmc/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/__init__.py
diff --git a/ironic/tests/unit/drivers/modules/ibmc/base.py b/ironic/tests/unit/drivers/modules/ibmc/base.py
new file mode 100644
index 000000000..cb337207e
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/base.py
@@ -0,0 +1,42 @@
+#
+# 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.
+"""Test base class for iBMC Driver."""
+
+import mock
+
+from ironic.drivers.modules.ibmc import utils
+from ironic.tests.unit.db import base as db_base
+from ironic.tests.unit.db import utils as db_utils
+from ironic.tests.unit.objects import utils as obj_utils
+
+
+class IBMCTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(IBMCTestCase, self).setUp()
+ self.driver_info = db_utils.get_test_ibmc_info()
+ self.config(enabled_hardware_types=['ibmc'],
+ enabled_power_interfaces=['ibmc'],
+ enabled_management_interfaces=['ibmc'],
+ enabled_vendor_interfaces=['ibmc'])
+ self.node = obj_utils.create_test_node(
+ self.context, driver='ibmc', driver_info=self.driver_info)
+ self.ibmc = utils.parse_driver_info(self.node)
+
+ @staticmethod
+ def mock_ibmc_conn(ibmc_client_connect):
+ conn = mock.Mock(system=mock.PropertyMock())
+ conn.__enter__ = mock.Mock(return_value=conn)
+ conn.__exit__ = mock.Mock(return_value=None)
+ ibmc_client_connect.return_value = conn
+ return conn
diff --git a/ironic/tests/unit/drivers/modules/ibmc/test_management.py b/ironic/tests/unit/drivers/modules/ibmc/test_management.py
new file mode 100644
index 000000000..d45a23304
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/test_management.py
@@ -0,0 +1,276 @@
+#
+# 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.
+"""Test class for iBMC Management interface."""
+
+import itertools
+
+import mock
+from oslo_utils import importutils
+
+from ironic.common import boot_devices
+from ironic.common import boot_modes
+from ironic.common import exception
+from ironic.conductor import task_manager
+from ironic.drivers.modules.ibmc import mappings
+from ironic.drivers.modules.ibmc import utils
+from ironic.tests.unit.drivers.modules.ibmc import base
+
+constants = importutils.try_import('ibmc_client.constants')
+ibmc_client = importutils.try_import('ibmc_client')
+ibmc_error = importutils.try_import('ibmc_client.exceptions')
+
+
+class IBMCManagementTestCase(base.IBMCTestCase):
+
+ def test_get_properties(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ properties = task.driver.get_properties()
+ for prop in utils.COMMON_PROPERTIES:
+ self.assertIn(prop, properties)
+
+ @mock.patch.object(utils, 'parse_driver_info', autospec=True)
+ def test_validate(self, mock_parse_driver_info):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.driver.management.validate(task)
+ mock_parse_driver_info.assert_called_once_with(task.node)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_get_supported_boot_devices(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock return value
+ _supported_boot_devices = list(mappings.GET_BOOT_DEVICE_MAP)
+ conn.system.get.return_value = mock.Mock(
+ boot_source_override=mock.Mock(
+ supported_boot_devices=_supported_boot_devices
+ )
+ )
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ supported_boot_devices = (
+ task.driver.management.get_supported_boot_devices(task))
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ expect = sorted(list(mappings.GET_BOOT_DEVICE_MAP.values()))
+ self.assertEqual(expect, sorted(supported_boot_devices))
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_boot_device(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock return value
+ conn.system.set_boot_source.return_value = None
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ device_mapping = [
+ (boot_devices.PXE, constants.BOOT_SOURCE_TARGET_PXE),
+ (boot_devices.DISK, constants.BOOT_SOURCE_TARGET_HDD),
+ (boot_devices.CDROM, constants.BOOT_SOURCE_TARGET_CD),
+ (boot_devices.BIOS,
+ constants.BOOT_SOURCE_TARGET_BIOS_SETUP),
+ ('floppy', constants.BOOT_SOURCE_TARGET_FLOPPY),
+ ]
+
+ persistent_mapping = [
+ (True, constants.BOOT_SOURCE_ENABLED_CONTINUOUS),
+ (False, constants.BOOT_SOURCE_ENABLED_ONCE)
+ ]
+
+ data_source = list(itertools.product(device_mapping,
+ persistent_mapping))
+ for (device, persistent) in data_source:
+ task.driver.management.set_boot_device(
+ task, device[0], persistent=persistent[0])
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ conn.system.set_boot_source.assert_called_once_with(
+ device[1],
+ enabled=persistent[1])
+ # Reset mocks
+ connect_ibmc.reset_mock()
+ conn.system.set_boot_source.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_boot_device_fail(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock return value
+ conn.system.set_boot_source.side_effect = (
+ ibmc_error.IBMCClientError
+ )
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaisesRegex(
+ exception.IBMCError, 'set iBMC boot device',
+ task.driver.management.set_boot_device, task,
+ boot_devices.PXE)
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ conn.system.set_boot_source.assert_called_once_with(
+ constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_ONCE)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_get_boot_device(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock return value
+ conn.system.get.return_value = mock.Mock(
+ boot_source_override=mock.Mock(
+ target=constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS
+ )
+ )
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ result_boot_device = task.driver.management.get_boot_device(task)
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ expected = {'boot_device': boot_devices.PXE,
+ 'persistent': True}
+ self.assertEqual(expected, result_boot_device)
+
+ def test_get_supported_boot_modes(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ supported_boot_modes = (
+ task.driver.management.get_supported_boot_modes(task))
+ self.assertEqual(list(mappings.SET_BOOT_MODE_MAP),
+ supported_boot_modes)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_boot_mode(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock system boot source override return value
+ conn.system.get.return_value = mock.Mock(
+ boot_source_override=mock.Mock(
+ target=constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS
+ )
+ )
+ conn.system.set_boot_source.return_value = None
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ expected_values = [
+ (boot_modes.LEGACY_BIOS, constants.BOOT_SOURCE_MODE_BIOS),
+ (boot_modes.UEFI, constants.BOOT_SOURCE_MODE_UEFI)
+ ]
+
+ for ironic_boot_mode, ibmc_boot_mode in expected_values:
+ task.driver.management.set_boot_mode(task,
+ mode=ironic_boot_mode)
+
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+
+ conn.system.set_boot_source.assert_called_once_with(
+ constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS,
+ mode=ibmc_boot_mode)
+
+ # Reset
+ connect_ibmc.reset_mock()
+ conn.system.set_boot_source.reset_mock()
+ conn.system.get.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_boot_mode_fail(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock system boot source override return value
+ conn.system.get.return_value = mock.Mock(
+ boot_source_override=mock.Mock(
+ target=constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS
+ )
+ )
+ conn.system.set_boot_source.side_effect = (
+ ibmc_error.IBMCClientError
+ )
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ expected_values = [
+ (boot_modes.LEGACY_BIOS, constants.BOOT_SOURCE_MODE_BIOS),
+ (boot_modes.UEFI, constants.BOOT_SOURCE_MODE_UEFI)
+ ]
+
+ for ironic_boot_mode, ibmc_boot_mode in expected_values:
+ self.assertRaisesRegex(
+ exception.IBMCError, 'set iBMC boot mode',
+ task.driver.management.set_boot_mode, task,
+ ironic_boot_mode)
+
+ conn.system.set_boot_source.assert_called_once_with(
+ constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS,
+ mode=ibmc_boot_mode)
+
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+
+ # Reset
+ connect_ibmc.reset_mock()
+ conn.system.set_boot_source.reset_mock()
+ conn.system.get.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_get_boot_mode(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock system boot source override return value
+ conn.system.get.return_value = mock.Mock(
+ boot_source_override=mock.Mock(
+ target=constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS,
+ mode=constants.BOOT_SOURCE_MODE_BIOS,
+ )
+ )
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ response = task.driver.management.get_boot_mode(task)
+
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+
+ expected = boot_modes.LEGACY_BIOS
+ self.assertEqual(expected, response)
+
+ def test_get_sensors_data(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ self.assertRaises(NotImplementedError,
+ task.driver.management.get_sensors_data, task)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_inject_nmi(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock system boot source override return value
+ conn.system.reset.return_value = None
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.management.inject_nmi(task)
+
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(constants.RESET_NMI)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_inject_nmi_fail(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # mock system boot source override return value
+ conn.system.reset.side_effect = (
+ ibmc_error.IBMCClientError
+ )
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaisesRegex(
+ exception.IBMCError, 'inject iBMC NMI',
+ task.driver.management.inject_nmi, task)
+
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(constants.RESET_NMI)
diff --git a/ironic/tests/unit/drivers/modules/ibmc/test_power.py b/ironic/tests/unit/drivers/modules/ibmc/test_power.py
new file mode 100644
index 000000000..39c5c78d9
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/test_power.py
@@ -0,0 +1,284 @@
+#
+# 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.
+"""Test class for iBMC Power interface."""
+
+import mock
+from oslo_utils import importutils
+
+from ironic.common import exception
+from ironic.common import states
+from ironic.conductor import task_manager
+from ironic.drivers.modules.ibmc import mappings
+from ironic.drivers.modules.ibmc import utils
+from ironic.tests.unit.drivers.modules.ibmc import base
+
+constants = importutils.try_import('ibmc_client.constants')
+ibmc_client = importutils.try_import('ibmc_client')
+ibmc_error = importutils.try_import('ibmc_client.exceptions')
+
+
+@mock.patch('eventlet.greenthread.sleep', lambda _t: None)
+class IBMCPowerTestCase(base.IBMCTestCase):
+
+ def test_get_properties(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ properties = task.driver.get_properties()
+ for prop in utils.COMMON_PROPERTIES:
+ self.assertIn(prop, properties)
+
+ @mock.patch.object(utils, 'parse_driver_info', autospec=True)
+ def test_validate(self, mock_parse_driver_info):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.driver.power.validate(task)
+ mock_parse_driver_info.assert_called_once_with(task.node)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_get_power_state(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ expected_values = mappings.GET_POWER_STATE_MAP
+ for current, expected in expected_values.items():
+ # Mock
+ conn.system.get.return_value = mock.Mock(
+ power_state=current
+ )
+
+ # Asserts
+ self.assertEqual(expected,
+ task.driver.power.get_power_state(task))
+
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+
+ # Reset Mock
+ conn.system.get.reset_mock()
+ connect_ibmc.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_power_state(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ state_mapping = mappings.SET_POWER_STATE_MAP
+ for (expect_state, reset_type) in state_mapping.items():
+ if expect_state in (states.POWER_OFF, states.SOFT_POWER_OFF):
+ final = constants.SYSTEM_POWER_STATE_OFF
+ transient = constants.SYSTEM_POWER_STATE_ON
+ else:
+ final = constants.SYSTEM_POWER_STATE_ON
+ transient = constants.SYSTEM_POWER_STATE_OFF
+
+ # Mocks
+ mock_system_get_results = (
+ [mock.Mock(power_state=transient)] * 3 +
+ [mock.Mock(power_state=final)])
+ conn.system.get.side_effect = mock_system_get_results
+
+ task.driver.power.set_power_state(task, expect_state)
+
+ # Asserts
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(reset_type)
+ self.assertEqual(4, conn.system.get.call_count)
+
+ # Reset Mocks
+ # TODO(Qianbiao.NG) why reset_mock does not reset call_count
+ connect_ibmc.reset_mock()
+ conn.system.get.reset_mock()
+ conn.system.reset.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_power_state_not_reached(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.config(power_state_change_timeout=2, group='conductor')
+
+ state_mapping = mappings.SET_POWER_STATE_MAP
+ for (expect_state, reset_type) in state_mapping.items():
+ if expect_state in (states.POWER_OFF, states.SOFT_POWER_OFF):
+ final = constants.SYSTEM_POWER_STATE_OFF
+ transient = constants.SYSTEM_POWER_STATE_ON
+ else:
+ final = constants.SYSTEM_POWER_STATE_ON
+ transient = constants.SYSTEM_POWER_STATE_OFF
+
+ # Mocks
+ mock_system_get_results = (
+ [mock.Mock(power_state=transient)] * 5 +
+ [mock.Mock(power_state=final)])
+ conn.system.get.side_effect = mock_system_get_results
+
+ self.assertRaises(exception.PowerStateFailure,
+ task.driver.power.set_power_state,
+ task, expect_state)
+
+ # Asserts
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(reset_type)
+
+ # Reset Mocks
+ connect_ibmc.reset_mock()
+ conn.system.get.reset_mock()
+ conn.system.reset.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_power_state_fail(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+
+ # Mocks
+ conn.system.reset.side_effect = (
+ ibmc_error.IBMCClientError
+ )
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ # Asserts
+ self.assertRaisesRegex(
+ exception.IBMCError, 'set iBMC power state',
+ task.driver.power.set_power_state, task, states.POWER_ON)
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(constants.RESET_ON)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_set_power_state_timeout(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.config(power_state_change_timeout=2, group='conductor')
+
+ # Mocks
+ conn.system.get.side_effect = (
+ [mock.Mock(power_state=constants.SYSTEM_POWER_STATE_OFF)] * 3
+ )
+
+ # Asserts
+ self.assertRaisesRegex(
+ exception.PowerStateFailure,
+ 'Failed to set node power state to power on',
+ task.driver.power.set_power_state, task, states.POWER_ON)
+
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(constants.RESET_ON)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_reboot(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.config(power_state_change_timeout=2, group='conductor')
+ expected_values = [
+ (constants.SYSTEM_POWER_STATE_OFF, constants.RESET_ON),
+ (constants.SYSTEM_POWER_STATE_ON,
+ constants.RESET_FORCE_RESTART)
+ ]
+
+ # for (expect_state, reset_type) in state_mapping.items():
+ for current, reset_type in expected_values:
+ mock_system_get_results = [
+ # Initial state
+ mock.Mock(power_state=current),
+ # Transient state - powering off
+ mock.Mock(power_state=constants.SYSTEM_POWER_STATE_OFF),
+ # Final state - down powering off
+ mock.Mock(power_state=constants.SYSTEM_POWER_STATE_ON)
+ ]
+ conn.system.get.side_effect = mock_system_get_results
+
+ task.driver.power.reboot(task)
+
+ # Asserts
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(reset_type)
+
+ # Reset Mocks
+ connect_ibmc.reset_mock()
+ conn.system.get.reset_mock()
+ conn.system.reset.reset_mock()
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_reboot_not_reached(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.config(power_state_change_timeout=2, group='conductor')
+
+ # Mocks
+ conn.system.get.return_value = mock.Mock(
+ power_state=constants.SYSTEM_POWER_STATE_OFF)
+ self.assertRaisesRegex(
+ exception.PowerStateFailure,
+ 'Failed to set node power state to power on',
+ task.driver.power.reboot, task)
+
+ # Asserts
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(constants.RESET_ON)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_reboot_fail(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+
+ # Mocks
+ conn.system.reset.side_effect = (
+ ibmc_error.IBMCClientError
+ )
+ conn.system.get.return_value = mock.Mock(
+ power_state=constants.SYSTEM_POWER_STATE_ON
+ )
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ # Asserts
+ self.assertRaisesRegex(
+ exception.IBMCError, 'reboot iBMC',
+ task.driver.power.reboot, task)
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.get.assert_called_once()
+ conn.system.reset.assert_called_once_with(
+ constants.RESET_FORCE_RESTART)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_reboot_timeout(self, connect_ibmc):
+ conn = self.mock_ibmc_conn(connect_ibmc)
+
+ # Mocks
+ conn.system.get.side_effect = [mock.Mock(
+ power_state=constants.SYSTEM_POWER_STATE_OFF
+ )] * 5
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.config(power_state_change_timeout=2, group='conductor')
+
+ # Asserts
+ self.assertRaisesRegex(
+ exception.PowerStateFailure,
+ 'Failed to set node power state to power on',
+ task.driver.power.reboot, task)
+
+ # Asserts
+ connect_ibmc.assert_called_with(**self.ibmc)
+ conn.system.reset.assert_called_once_with(
+ constants.RESET_ON)
+
+ def test_get_supported_power_states(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ supported_power_states = (
+ task.driver.power.get_supported_power_states(task))
+ self.assertEqual(sorted(list(mappings.SET_POWER_STATE_MAP)),
+ sorted(supported_power_states))
diff --git a/ironic/tests/unit/drivers/modules/ibmc/test_utils.py b/ironic/tests/unit/drivers/modules/ibmc/test_utils.py
new file mode 100644
index 000000000..7863ced5b
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/test_utils.py
@@ -0,0 +1,172 @@
+#
+# 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.
+"""Test class for iBMC Driver common utils."""
+
+import copy
+import os
+
+import mock
+from oslo_utils import importutils
+
+from ironic.common import exception
+from ironic.conductor import task_manager
+from ironic.drivers.modules.ibmc import utils
+from ironic.tests.unit.drivers.modules.ibmc import base
+
+constants = importutils.try_import('ibmc_client.constants')
+ibmc_client = importutils.try_import('ibmc_client')
+ibmc_error = importutils.try_import('ibmc_client.exceptions')
+
+
+class IBMCUtilsTestCase(base.IBMCTestCase):
+
+ def setUp(self):
+ super(IBMCUtilsTestCase, self).setUp()
+ # Redfish specific configurations
+ self.config(connection_attempts=2, group='ibmc')
+ self.parsed_driver_info = {
+ 'address': 'https://example.com',
+ 'username': 'username',
+ 'password': 'password',
+ 'verify_ca': True,
+ }
+
+ def test_parse_driver_info(self):
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+
+ def test_parse_driver_info_default_scheme(self):
+ self.node.driver_info['ibmc_address'] = 'example.com'
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+
+ def test_parse_driver_info_default_scheme_with_port(self):
+ self.node.driver_info['ibmc_address'] = 'example.com:42'
+ self.parsed_driver_info['address'] = 'https://example.com:42'
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+
+ def test_parse_driver_info_missing_info(self):
+ for prop in utils.REQUIRED_PROPERTIES:
+ self.node.driver_info = self.driver_info.copy()
+ self.node.driver_info.pop(prop)
+ self.assertRaises(exception.MissingParameterValue,
+ utils.parse_driver_info, self.node)
+
+ def test_parse_driver_info_invalid_address(self):
+ for value in ['/banana!', '#location', '?search=hello']:
+ self.node.driver_info['ibmc_address'] = value
+ self.assertRaisesRegex(exception.InvalidParameterValue,
+ 'Invalid iBMC address',
+ utils.parse_driver_info, self.node)
+
+ @mock.patch.object(os.path, 'isdir', autospec=True)
+ def test_parse_driver_info_path_verify_ca(self,
+ mock_isdir):
+ mock_isdir.return_value = True
+ fake_path = '/path/to/a/valid/CA'
+ self.node.driver_info['ibmc_verify_ca'] = fake_path
+ self.parsed_driver_info['verify_ca'] = fake_path
+
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+ mock_isdir.assert_called_once_with(fake_path)
+
+ @mock.patch.object(os.path, 'isfile', autospec=True)
+ def test_parse_driver_info_valid_capath(self, mock_isfile):
+ mock_isfile.return_value = True
+ fake_path = '/path/to/a/valid/CA.pem'
+ self.node.driver_info['ibmc_verify_ca'] = fake_path
+ self.parsed_driver_info['verify_ca'] = fake_path
+
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+ mock_isfile.assert_called_once_with(fake_path)
+
+ def test_parse_driver_info_invalid_value_verify_ca(self):
+ # Integers are not supported
+ self.node.driver_info['ibmc_verify_ca'] = 123456
+ self.assertRaisesRegex(exception.InvalidParameterValue,
+ 'Invalid value type',
+ utils.parse_driver_info, self.node)
+
+ def test_parse_driver_info_valid_string_value_verify_ca(self):
+ for value in ('0', 'f', 'false', 'off', 'n', 'no'):
+ self.node.driver_info['ibmc_verify_ca'] = value
+ response = utils.parse_driver_info(self.node)
+ parsed_driver_info = copy.deepcopy(self.parsed_driver_info)
+ parsed_driver_info['verify_ca'] = False
+ self.assertEqual(parsed_driver_info, response)
+
+ for value in ('1', 't', 'true', 'on', 'y', 'yes'):
+ self.node.driver_info['ibmc_verify_ca'] = value
+ response = utils.parse_driver_info(self.node)
+ self.assertEqual(self.parsed_driver_info, response)
+
+ def test_parse_driver_info_invalid_string_value_verify_ca(self):
+ for value in ('xyz', '*', '!123', '123'):
+ self.node.driver_info['ibmc_verify_ca'] = value
+ self.assertRaisesRegex(exception.InvalidParameterValue,
+ 'The value should be a Boolean',
+ utils.parse_driver_info, self.node)
+
+ def test_revert_dictionary(self):
+ data = {
+ "key1": "value1",
+ "key2": "value2"
+ }
+
+ revert = utils.revert_dictionary(data)
+ self.assertEqual({
+ "value1": "key1",
+ "value2": "key2"
+ }, revert)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_handle_ibmc_exception_retry(self, connect_ibmc):
+
+ @utils.handle_ibmc_exception('get IBMC system')
+ def get_ibmc_system(_task):
+ driver_info = utils.parse_driver_info(_task.node)
+ with ibmc_client.connect(**driver_info) as _conn:
+ return _conn.system.get()
+
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ # Mocks
+ conn.system.get.side_effect = [
+ ibmc_error.ConnectionError(url=self.ibmc['address'],
+ error='Failed to connect to host'),
+ mock.PropertyMock(
+ boot_source_override=mock.PropertyMock(
+ target=constants.BOOT_SOURCE_TARGET_PXE,
+ enabled=constants.BOOT_SOURCE_ENABLED_CONTINUOUS
+ )
+ )
+ ]
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ system = get_ibmc_system(task)
+
+ # Asserts
+ self.assertEqual(constants.BOOT_SOURCE_TARGET_PXE,
+ system.boot_source_override.target)
+ self.assertEqual(constants.BOOT_SOURCE_ENABLED_CONTINUOUS,
+ system.boot_source_override.enabled)
+
+ # 1 failed, 1 succeed
+ connect_ibmc.assert_called_with(**self.ibmc)
+ self.assertEqual(2, connect_ibmc.call_count)
+
+ # 1 failed, 1 succeed
+ self.assertEqual(2, conn.system.get.call_count)
diff --git a/ironic/tests/unit/drivers/modules/ibmc/test_vendor.py b/ironic/tests/unit/drivers/modules/ibmc/test_vendor.py
new file mode 100644
index 000000000..3a316e0d8
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/ibmc/test_vendor.py
@@ -0,0 +1,60 @@
+#
+# 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.
+"""Test class for iBMC vendor interface."""
+
+import mock
+from oslo_utils import importutils
+
+from ironic.conductor import task_manager
+from ironic.drivers.modules.ibmc import utils
+from ironic.tests.unit.drivers.modules.ibmc import base
+
+ibmc_client = importutils.try_import('ibmc_client')
+
+
+@mock.patch('eventlet.greenthread.sleep', lambda _t: None)
+class IBMCVendorTestCase(base.IBMCTestCase):
+
+ def setUp(self):
+ super(IBMCVendorTestCase, self).setUp()
+
+ def test_get_properties(self):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ properties = task.driver.get_properties()
+ for prop in utils.COMMON_PROPERTIES:
+ self.assertIn(prop, properties)
+
+ @mock.patch.object(utils, 'parse_driver_info', autospec=True)
+ def test_validate(self, mock_parse_driver_info):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.driver.power.validate(task)
+ mock_parse_driver_info.assert_called_once_with(task.node)
+
+ @mock.patch.object(ibmc_client, 'connect', autospec=True)
+ def test_list_boot_type_order(self, connect_ibmc):
+ # Mocks
+ conn = self.mock_ibmc_conn(connect_ibmc)
+ boot_up_seq = ['Pxe', 'Hdd', 'Others', 'Cd']
+ conn.system.get.return_value = mock.Mock(
+ boot_sequence=['Pxe', 'Hdd', 'Others', 'Cd']
+ )
+
+ expected = {'boot_up_sequence': boot_up_seq}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ seq = task.driver.vendor.boot_up_seq(task)
+ conn.system.get.assert_called_once()
+ connect_ibmc.assert_called_once_with(**self.ibmc)
+ self.assertEqual(expected, seq)
diff --git a/ironic/tests/unit/drivers/test_ibmc.py b/ironic/tests/unit/drivers/test_ibmc.py
new file mode 100644
index 000000000..731311b54
--- /dev/null
+++ b/ironic/tests/unit/drivers/test_ibmc.py
@@ -0,0 +1,47 @@
+#
+# 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.
+
+# Version 1.0.0
+
+from ironic.conductor import task_manager
+from ironic.drivers.modules.ibmc import management as ibmc_mgmt
+from ironic.drivers.modules.ibmc import power as ibmc_power
+from ironic.drivers.modules.ibmc import vendor as ibmc_vendor
+from ironic.drivers.modules import iscsi_deploy
+from ironic.drivers.modules import noop
+from ironic.drivers.modules import pxe
+from ironic.tests.unit.db import base as db_base
+from ironic.tests.unit.objects import utils as obj_utils
+
+
+class IBMCHardwareTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(IBMCHardwareTestCase, self).setUp()
+ self.config(enabled_hardware_types=['ibmc'],
+ enabled_power_interfaces=['ibmc'],
+ enabled_management_interfaces=['ibmc'],
+ enabled_vendor_interfaces=['ibmc'])
+
+ def test_default_interfaces(self):
+ node = obj_utils.create_test_node(self.context, driver='ibmc')
+ with task_manager.acquire(self.context, node.id) as task:
+ self.assertIsInstance(task.driver.management,
+ ibmc_mgmt.IBMCManagement)
+ self.assertIsInstance(task.driver.power,
+ ibmc_power.IBMCPower)
+ self.assertIsInstance(task.driver.boot, pxe.PXEBoot)
+ self.assertIsInstance(task.driver.deploy, iscsi_deploy.ISCSIDeploy)
+ self.assertIsInstance(task.driver.console, noop.NoConsole)
+ self.assertIsInstance(task.driver.raid, noop.NoRAID)
+ self.assertIsInstance(task.driver.vendor, ibmc_vendor.IBMCVendor)
diff --git a/ironic/tests/unit/drivers/third_party_driver_mock_specs.py b/ironic/tests/unit/drivers/third_party_driver_mock_specs.py
index 6a5f906af..49660c4ad 100644
--- a/ironic/tests/unit/drivers/third_party_driver_mock_specs.py
+++ b/ironic/tests/unit/drivers/third_party_driver_mock_specs.py
@@ -170,3 +170,10 @@ XCLARITY_STATES_SPEC = (
'STATE_POWER_OFF',
'STATE_POWER_ON',
)
+
+# python-ibmcclient
+IBMCCLIENT_SPEC = (
+ 'connect',
+ 'exceptions',
+ 'constants',
+)
diff --git a/ironic/tests/unit/drivers/third_party_driver_mocks.py b/ironic/tests/unit/drivers/third_party_driver_mocks.py
index db82dfe7b..6e6b188de 100644
--- a/ironic/tests/unit/drivers/third_party_driver_mocks.py
+++ b/ironic/tests/unit/drivers/third_party_driver_mocks.py
@@ -26,6 +26,7 @@ Current list of mocked libraries:
- pysnmp
- scciclient
- python-dracclient
+- python-ibmcclient
"""
import sys
@@ -263,3 +264,45 @@ if not xclarity_client:
xclarity_client.exceptions.XClarityException = type('XClarityException',
(Exception,), {})
sys.modules['xclarity_client.models'] = xclarity_client.models
+
+
+# python-ibmcclient mocks for HUAWEI rack server driver
+ibmc_client = importutils.try_import('ibmc_client')
+if not ibmc_client:
+ ibmc_client = mock.MagicMock(spec_set=mock_specs.IBMCCLIENT_SPEC)
+ sys.modules['ibmc_client'] = ibmc_client
+
+ # Mock iBMC client exceptions
+ exceptions = mock.MagicMock()
+ exceptions.ConnectionError = (
+ type('ConnectionError', (MockKwargsException,), {}))
+ exceptions.IBMCClientError = (
+ type('IBMCClientError', (MockKwargsException,), {}))
+ sys.modules['ibmc_client.exceptions'] = exceptions
+
+ # Mock iIBMC client constants
+ constants = mock.MagicMock(
+ SYSTEM_POWER_STATE_ON='On',
+ SYSTEM_POWER_STATE_OFF='Off',
+ BOOT_SOURCE_TARGET_NONE='None',
+ BOOT_SOURCE_TARGET_PXE='Pxe',
+ BOOT_SOURCE_TARGET_FLOPPY='Floppy',
+ BOOT_SOURCE_TARGET_CD='Cd',
+ BOOT_SOURCE_TARGET_HDD='Hdd',
+ BOOT_SOURCE_TARGET_BIOS_SETUP='BiosSetup',
+ BOOT_SOURCE_MODE_BIOS='Legacy',
+ BOOT_SOURCE_MODE_UEFI='UEFI',
+ BOOT_SOURCE_ENABLED_ONCE='Once',
+ BOOT_SOURCE_ENABLED_CONTINUOUS='Continuous',
+ BOOT_SOURCE_ENABLED_DISABLED='Disabled',
+ RESET_NMI='Nmi',
+ RESET_ON='On',
+ RESET_FORCE_OFF='ForceOff',
+ RESET_GRACEFUL_SHUTDOWN='GracefulShutdown',
+ RESET_FORCE_RESTART='ForceRestart',
+ RESET_FORCE_POWER_CYCLE='ForcePowerCycle')
+ sys.modules['ibmc_client.constants'] = constants
+
+ if 'ironic.drivers.modules.ibmc' in sys.modules:
+ six.moves.reload_module(
+ sys.modules['ironic.drivers.modules.ibmc'])
diff --git a/releasenotes/notes/ibmc-driver-45fcf9f50ebf0193.yaml b/releasenotes/notes/ibmc-driver-45fcf9f50ebf0193.yaml
new file mode 100644
index 000000000..f58c4bb4d
--- /dev/null
+++ b/releasenotes/notes/ibmc-driver-45fcf9f50ebf0193.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Adds a new hardware type ``ibmc`` for HUAWEI 2288H V5, CH121 V5 series
+ servers. This hardware type supports PXE based boot using HUAWEI iBMC
+ RESTful APIs. The following driver interfaces are supported:
+
+ * management: ``ibmc``
+ * power: ``ibmc``
+ * vendor: ``ibmc``
diff --git a/setup.cfg b/setup.cfg
index cfab34dd3..7638c911f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -95,6 +95,7 @@ ironic.hardware.interfaces.inspect =
ironic.hardware.interfaces.management =
cimc = ironic.drivers.modules.cimc.management:CIMCManagement
fake = ironic.drivers.modules.fake:FakeManagement
+ ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
idrac = ironic.drivers.modules.drac.management:DracManagement
ilo = ironic.drivers.modules.ilo.management:IloManagement
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
@@ -112,6 +113,7 @@ ironic.hardware.interfaces.network =
ironic.hardware.interfaces.power =
cimc = ironic.drivers.modules.cimc.power:Power
fake = ironic.drivers.modules.fake:FakePower
+ ibmc = ironic.drivers.modules.ibmc.power:IBMCPower
idrac = ironic.drivers.modules.drac.power:DracPower
ilo = ironic.drivers.modules.ilo.power:IloPower
ipmitool = ironic.drivers.modules.ipmitool:IPMIPower
@@ -142,6 +144,7 @@ ironic.hardware.interfaces.storage =
ironic.hardware.interfaces.vendor =
fake = ironic.drivers.modules.fake:FakeVendorB
+ ibmc = ironic.drivers.modules.ibmc.vendor:IBMCVendor
idrac = ironic.drivers.modules.drac.vendor_passthru:DracVendorPassthru
ilo = ironic.drivers.modules.ilo.vendor:VendorPassthru
ipmitool = ironic.drivers.modules.ipmitool:VendorPassthru
@@ -151,6 +154,7 @@ ironic.hardware.types =
cisco-ucs-managed = ironic.drivers.cisco_ucs:CiscoUCSManaged
cisco-ucs-standalone = ironic.drivers.cisco_ucs:CiscoUCSStandalone
fake-hardware = ironic.drivers.fake_hardware:FakeHardware
+ ibmc = ironic.drivers.ibmc:IBMCHardware
idrac = ironic.drivers.drac:IDRACHardware
ilo = ironic.drivers.ilo:IloHardware
ilo5 = ironic.drivers.ilo:Ilo5Hardware