Browse Source

Added new plugin version with node & nic attributes support

* Added new plugin version supported by Fuel >= v9.0
* Added validation for node/nic/bond plugin node's attributes

Change-Id: I3e059940b910e67cca9b02a4d29179fa985414ff
Implements: blueprint nics-and-nodes-attributes-via-plugin
Elena Kosareva 2 years ago
parent
commit
6dbc520503
32 changed files with 1205 additions and 4 deletions
  1. 202
    0
      examples/fuel_plugin_example_v5/LICENSE
  2. 4
    0
      examples/fuel_plugin_example_v5/README.md
  3. 18
    0
      examples/fuel_plugin_example_v5/bond_config.yaml
  4. 17
    0
      examples/fuel_plugin_example_v5/components.yaml
  5. 14
    0
      examples/fuel_plugin_example_v5/deployment_scripts/deploy.pp
  6. 23
    0
      examples/fuel_plugin_example_v5/deployment_scripts/deploy.sh
  7. 46
    0
      examples/fuel_plugin_example_v5/deployment_tasks.yaml
  8. 15
    0
      examples/fuel_plugin_example_v5/environment_config.yaml
  9. 26
    0
      examples/fuel_plugin_example_v5/fuel-simple-service.py
  10. 40
    0
      examples/fuel_plugin_example_v5/metadata.yaml
  11. 24
    0
      examples/fuel_plugin_example_v5/network_roles.yaml
  12. 18
    0
      examples/fuel_plugin_example_v5/nic_config.yaml
  13. 25
    0
      examples/fuel_plugin_example_v5/node_config.yaml
  14. 6
    0
      examples/fuel_plugin_example_v5/node_roles.yaml
  15. 21
    0
      examples/fuel_plugin_example_v5/pre_build_hook
  16. 0
    0
      examples/fuel_plugin_example_v5/repositories/centos/.gitkeep
  17. 0
    0
      examples/fuel_plugin_example_v5/repositories/ubuntu/.gitkeep
  18. 6
    0
      examples/fuel_plugin_example_v5/volumes.yaml
  19. 1
    0
      fuel_plugin_builder/actions/__init__.py
  20. 4
    0
      fuel_plugin_builder/actions/build.py
  21. 15
    0
      fuel_plugin_builder/templates/v5/plugin_data/bond_config.yaml.mako
  22. 38
    0
      fuel_plugin_builder/templates/v5/plugin_data/metadata.yaml.mako
  23. 15
    0
      fuel_plugin_builder/templates/v5/plugin_data/nic_config.yaml.mako
  24. 19
    0
      fuel_plugin_builder/templates/v5/plugin_data/node_config.yaml.mako
  25. 3
    2
      fuel_plugin_builder/tests/test_validator_v4.py
  26. 452
    0
      fuel_plugin_builder/tests/test_validator_v5.py
  27. 13
    0
      fuel_plugin_builder/tests/test_version_mapping.py
  28. 1
    0
      fuel_plugin_builder/validators/__init__.py
  29. 1
    0
      fuel_plugin_builder/validators/schemas/__init__.py
  30. 77
    0
      fuel_plugin_builder/validators/schemas/v5.py
  31. 51
    0
      fuel_plugin_builder/validators/validator_v5.py
  32. 10
    2
      fuel_plugin_builder/version_mapping.py

+ 202
- 0
examples/fuel_plugin_example_v5/LICENSE View File

@@ -0,0 +1,202 @@
1
+Apache License
2
+                           Version 2.0, January 2004
3
+                        http://www.apache.org/licenses/
4
+
5
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+   1. Definitions.
8
+
9
+      "License" shall mean the terms and conditions for use, reproduction,
10
+      and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+      "Licensor" shall mean the copyright owner or entity authorized by
13
+      the copyright owner that is granting the License.
14
+
15
+      "Legal Entity" shall mean the union of the acting entity and all
16
+      other entities that control, are controlled by, or are under common
17
+      control with that entity. For the purposes of this definition,
18
+      "control" means (i) the power, direct or indirect, to cause the
19
+      direction or management of such entity, whether by contract or
20
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+      outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+      "You" (or "Your") shall mean an individual or Legal Entity
24
+      exercising permissions granted by this License.
25
+
26
+      "Source" form shall mean the preferred form for making modifications,
27
+      including but not limited to software source code, documentation
28
+      source, and configuration files.
29
+
30
+      "Object" form shall mean any form resulting from mechanical
31
+      transformation or translation of a Source form, including but
32
+      not limited to compiled object code, generated documentation,
33
+      and conversions to other media types.
34
+
35
+      "Work" shall mean the work of authorship, whether in Source or
36
+      Object form, made available under the License, as indicated by a
37
+      copyright notice that is included in or attached to the work
38
+      (an example is provided in the Appendix below).
39
+
40
+      "Derivative Works" shall mean any work, whether in Source or Object
41
+      form, that is based on (or derived from) the Work and for which the
42
+      editorial revisions, annotations, elaborations, or other modifications
43
+      represent, as a whole, an original work of authorship. For the purposes
44
+      of this License, Derivative Works shall not include works that remain
45
+      separable from, or merely link (or bind by name) to the interfaces of,
46
+      the Work and Derivative Works thereof.
47
+
48
+      "Contribution" shall mean any work of authorship, including
49
+      the original version of the Work and any modifications or additions
50
+      to that Work or Derivative Works thereof, that is intentionally
51
+      submitted to Licensor for inclusion in the Work by the copyright owner
52
+      or by an individual or Legal Entity authorized to submit on behalf of
53
+      the copyright owner. For the purposes of this definition, "submitted"
54
+      means any form of electronic, verbal, or written communication sent
55
+      to the Licensor or its representatives, including but not limited to
56
+      communication on electronic mailing lists, source code control systems,
57
+      and issue tracking systems that are managed by, or on behalf of, the
58
+      Licensor for the purpose of discussing and improving the Work, but
59
+      excluding communication that is conspicuously marked or otherwise
60
+      designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+      "Contributor" shall mean Licensor and any individual or Legal Entity
63
+      on behalf of whom a Contribution has been received by Licensor and
64
+      subsequently incorporated within the Work.
65
+
66
+   2. Grant of Copyright License. Subject to the terms and conditions of
67
+      this License, each Contributor hereby grants to You a perpetual,
68
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+      copyright license to reproduce, prepare Derivative Works of,
70
+      publicly display, publicly perform, sublicense, and distribute the
71
+      Work and such Derivative Works in Source or Object form.
72
+
73
+   3. Grant of Patent License. Subject to the terms and conditions of
74
+      this License, each Contributor hereby grants to You a perpetual,
75
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+      (except as stated in this section) patent license to make, have made,
77
+      use, offer to sell, sell, import, and otherwise transfer the Work,
78
+      where such license applies only to those patent claims licensable
79
+      by such Contributor that are necessarily infringed by their
80
+      Contribution(s) alone or by combination of their Contribution(s)
81
+      with the Work to which such Contribution(s) was submitted. If You
82
+      institute patent litigation against any entity (including a
83
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+      or a Contribution incorporated within the Work constitutes direct
85
+      or contributory patent infringement, then any patent licenses
86
+      granted to You under this License for that Work shall terminate
87
+      as of the date such litigation is filed.
88
+
89
+   4. Redistribution. You may reproduce and distribute copies of the
90
+      Work or Derivative Works thereof in any medium, with or without
91
+      modifications, and in Source or Object form, provided that You
92
+      meet the following conditions:
93
+
94
+      (a) You must give any other recipients of the Work or
95
+          Derivative Works a copy of this License; and
96
+
97
+      (b) You must cause any modified files to carry prominent notices
98
+          stating that You changed the files; and
99
+
100
+      (c) You must retain, in the Source form of any Derivative Works
101
+          that You distribute, all copyright, patent, trademark, and
102
+          attribution notices from the Source form of the Work,
103
+          excluding those notices that do not pertain to any part of
104
+          the Derivative Works; and
105
+
106
+      (d) If the Work includes a "NOTICE" text file as part of its
107
+          distribution, then any Derivative Works that You distribute must
108
+          include a readable copy of the attribution notices contained
109
+          within such NOTICE file, excluding those notices that do not
110
+          pertain to any part of the Derivative Works, in at least one
111
+          of the following places: within a NOTICE text file distributed
112
+          as part of the Derivative Works; within the Source form or
113
+          documentation, if provided along with the Derivative Works; or,
114
+          within a display generated by the Derivative Works, if and
115
+          wherever such third-party notices normally appear. The contents
116
+          of the NOTICE file are for informational purposes only and
117
+          do not modify the License. You may add Your own attribution
118
+          notices within Derivative Works that You distribute, alongside
119
+          or as an addendum to the NOTICE text from the Work, provided
120
+          that such additional attribution notices cannot be construed
121
+          as modifying the License.
122
+
123
+      You may add Your own copyright statement to Your modifications and
124
+      may provide additional or different license terms and conditions
125
+      for use, reproduction, or distribution of Your modifications, or
126
+      for any such Derivative Works as a whole, provided Your use,
127
+      reproduction, and distribution of the Work otherwise complies with
128
+      the conditions stated in this License.
129
+
130
+   5. Submission of Contributions. Unless You explicitly state otherwise,
131
+      any Contribution intentionally submitted for inclusion in the Work
132
+      by You to the Licensor shall be under the terms and conditions of
133
+      this License, without any additional terms or conditions.
134
+      Notwithstanding the above, nothing herein shall supersede or modify
135
+      the terms of any separate license agreement you may have executed
136
+      with Licensor regarding such Contributions.
137
+
138
+   6. Trademarks. This License does not grant permission to use the trade
139
+      names, trademarks, service marks, or product names of the Licensor,
140
+      except as required for reasonable and customary use in describing the
141
+      origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+   7. Disclaimer of Warranty. Unless required by applicable law or
144
+      agreed to in writing, Licensor provides the Work (and each
145
+      Contributor provides its Contributions) on an "AS IS" BASIS,
146
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+      implied, including, without limitation, any warranties or conditions
148
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+      PARTICULAR PURPOSE. You are solely responsible for determining the
150
+      appropriateness of using or redistributing the Work and assume any
151
+      risks associated with Your exercise of permissions under this License.
152
+
153
+   8. Limitation of Liability. In no event and under no legal theory,
154
+      whether in tort (including negligence), contract, or otherwise,
155
+      unless required by applicable law (such as deliberate and grossly
156
+      negligent acts) or agreed to in writing, shall any Contributor be
157
+      liable to You for damages, including any direct, indirect, special,
158
+      incidental, or consequential damages of any character arising as a
159
+      result of this License or out of the use or inability to use the
160
+      Work (including but not limited to damages for loss of goodwill,
161
+      work stoppage, computer failure or malfunction, or any and all
162
+      other commercial damages or losses), even if such Contributor
163
+      has been advised of the possibility of such damages.
164
+
165
+   9. Accepting Warranty or Additional Liability. While redistributing
166
+      the Work or Derivative Works thereof, You may choose to offer,
167
+      and charge a fee for, acceptance of support, warranty, indemnity,
168
+      or other liability obligations and/or rights consistent with this
169
+      License. However, in accepting such obligations, You may act only
170
+      on Your own behalf and on Your sole responsibility, not on behalf
171
+      of any other Contributor, and only if You agree to indemnify,
172
+      defend, and hold each Contributor harmless for any liability
173
+      incurred by, or claims asserted against, such Contributor by reason
174
+      of your accepting any such warranty or additional liability.
175
+
176
+   END OF TERMS AND CONDITIONS
177
+
178
+   APPENDIX: How to apply the Apache License to your work.
179
+
180
+      To apply the Apache License to your work, attach the following
181
+      boilerplate notice, with the fields enclosed by brackets "{}"
182
+      replaced with your own identifying information. (Don't include
183
+      the brackets!)  The text should be enclosed in the appropriate
184
+      comment syntax for the file format. We also recommend that a
185
+      file or class name and description of purpose be included on the
186
+      same "printed page" as the copyright notice for easier
187
+      identification within third-party archives.
188
+
189
+   Copyright {yyyy} {name of copyright owner}
190
+
191
+   Licensed under the Apache License, Version 2.0 (the "License");
192
+   you may not use this file except in compliance with the License.
193
+   You may obtain a copy of the License at
194
+
195
+       http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+   Unless required by applicable law or agreed to in writing, software
198
+   distributed under the License is distributed on an "AS IS" BASIS,
199
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+   See the License for the specific language governing permissions and
201
+   limitations under the License.
202
+

+ 4
- 0
examples/fuel_plugin_example_v5/README.md View File

@@ -0,0 +1,4 @@
1
+fuel_plugin_example_v5
2
+======================
3
+
4
+Plugin description

+ 18
- 0
examples/fuel_plugin_example_v5/bond_config.yaml View File

@@ -0,0 +1,18 @@
1
+# This file contains additional bond attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+attribute_a:
7
+  label: "Bond attribute A"
8
+  description: "Some description"
9
+  type: "text"
10
+  value: ""
11
+  restrictions:
12
+    - condition: "settings:common.libvirt_type.value != 'kvm'"
13
+      action: "hide"
14
+attribute_b:
15
+  label: "Bond attribute B"
16
+  description: "Some description"
17
+  type: "checkbox"
18
+  value: false

+ 17
- 0
examples/fuel_plugin_example_v5/components.yaml View File

@@ -0,0 +1,17 @@
1
+# This file contains wizard components descriptions that are pretty similar to
2
+# the `environment_config.yaml`.
3
+# Please, take a look at following link for the details:
4
+# - https://blueprints.launchpad.net/fuel/+spec/component-registry
5
+# - https://specs.openstack.org/openstack/fuel-specs/specs/8.0/component-registry.html
6
+
7
+- name: additional_service:service_plugin_v5_component
8
+  label: "Title for service_plugin_v5_component component."
9
+  description: "Description for service_plugin_v5_component component."
10
+  compatible:
11
+    - name: "hypervisor:xxx"
12
+  requires:
13
+    - name: "hypervisor:xxx"
14
+      message: "service_plugin_v5_component requires XXX compute."
15
+  incompatible:
16
+    - name: "network:neutron:*"
17
+      message: "service_plugin_v5_component incompatible with Neutron network."

+ 14
- 0
examples/fuel_plugin_example_v5/deployment_scripts/deploy.pp View File

@@ -0,0 +1,14 @@
1
+# This puppet manifest creates example file in /tmp folder.
2
+
3
+notice('PLUGIN: fuel_plugin_example_v5 - deploy.pp')
4
+
5
+class fuel_plugin_example_v5 {
6
+  file { '/tmp/fuel_plugin_example_v5_puppet':
7
+      owner   => 'root',
8
+      group   => 'root',
9
+      mode    => 0644,
10
+      content => "fuel_plugin_example_v5\n",
11
+  }
12
+}
13
+
14
+class {'fuel_plugin_example_v5': }

+ 23
- 0
examples/fuel_plugin_example_v5/deployment_scripts/deploy.sh View File

@@ -0,0 +1,23 @@
1
+#!/bin/bash
2
+set -eux
3
+
4
+# It's a script which deploys your plugin
5
+echo fuel_plugin_example_v5 > /tmp/fuel_plugin_example_v5_sh
6
+
7
+OS_NAME=''
8
+if   grep -i CentOS /etc/issue.net >/dev/null; then
9
+    OS_NAME='centos';
10
+elif grep -i Ubuntu /etc/issue.net >/dev/null; then
11
+    OS_NAME='ubuntu';
12
+fi
13
+
14
+function install_package {
15
+    if [ $OS_NAME == 'ubuntu' ]; then
16
+        apt-get install -y --force-yes -o 'APT::Get::AllowUnauthenticated=1' fuel-simple-service
17
+    elif [ $OS_NAME == 'centos' ]; then
18
+        yum install -y fuel-simple-service
19
+    fi
20
+}
21
+
22
+install_package
23
+fuel-simple-service.py &

+ 46
- 0
examples/fuel_plugin_example_v5/deployment_tasks.yaml View File

@@ -0,0 +1,46 @@
1
+- id: fuel_plugin_example_v5
2
+  type: group
3
+  role: [fuel_plugin_example_v5]
4
+  tasks:
5
+    - hiera
6
+    - globals
7
+  required_for: [deploy_end]
8
+  requires: [deploy_start]
9
+  parameters:
10
+    strategy:
11
+      type: parallel
12
+
13
+- id: fuel_plugin_example_v5-controller-deployment
14
+  type: puppet
15
+  version: 2.0.0
16
+  groups: [primary-controller, controller]
17
+  required_for: [connectivity_tests, deploy_end]
18
+  requires: [netconfig, deploy_start]
19
+  parameters:
20
+    puppet_manifest: "deploy.pp"
21
+    puppet_modules: "."
22
+    timeout: 3600
23
+
24
+- id: fuel_plugin_example_v5-deployment
25
+  type: puppet
26
+  version: 2.0.0
27
+  groups: [fuel_plugin_example_v5]
28
+  required_for: [deploy_end]
29
+  requires: [deploy_start]
30
+  parameters:
31
+    puppet_manifest: "deploy.pp"
32
+    puppet_modules: "."
33
+    timeout: 3600
34
+    retries: 10
35
+
36
+- id: fuel_plugin_example_v5-post-deployment-sh
37
+  type: shell
38
+  version: 2.0.0
39
+  role: [fuel_plugin_example_v5]
40
+  required_for: [post_deployment_end]
41
+  requires: [post_deployment_start]
42
+  parameters:
43
+    cmd: bash deploy.sh
44
+    retries: 3
45
+    interval: 20
46
+    timeout: 180

+ 15
- 0
examples/fuel_plugin_example_v5/environment_config.yaml View File

@@ -0,0 +1,15 @@
1
+# This file describes additional attributes that will appear on the Settings
2
+# tab of the Fuel web UI. When the environment is deployed, these attributes
3
+# are passed to the task executor so that the data is available
4
+# in the /etc/astute.yaml file on each target node and can be accessed from
5
+# your bash or puppet scripts.
6
+
7
+attributes:
8
+  metadata:
9
+    group: 'other'
10
+  fuel_plugin_example_v5_text:
11
+    value: 'Set default value'
12
+    label: 'Text field'
13
+    description: 'Description for text field'
14
+    weight: 25
15
+    type: "text"

+ 26
- 0
examples/fuel_plugin_example_v5/fuel-simple-service.py View File

@@ -0,0 +1,26 @@
1
+#!/usr/bin/env python
2
+# -*- encoding: utf-8 -*-
3
+
4
+from wsgiref.simple_server import make_server
5
+
6
+def web_app(environ, start_response):
7
+    status = '200 OK'
8
+    headers = [('Content-type', 'text/plain')]
9
+
10
+    start_response(status, headers)
11
+
12
+    return open('/etc/astute.yaml').read()
13
+
14
+
15
+def start_server(host, port):
16
+    httpd = make_server(host, port, web_app)
17
+    print 'Started server 8234'
18
+    httpd.serve_forever()
19
+
20
+
21
+def main():
22
+    start_server('', 8234)
23
+
24
+
25
+if __name__ == '__main__':
26
+    main()

+ 40
- 0
examples/fuel_plugin_example_v5/metadata.yaml View File

@@ -0,0 +1,40 @@
1
+# Plugin name
2
+name: fuel_plugin_example_v5
3
+# Human-readable name for your plugin
4
+title: Title for fuel_plugin_example_v5 plugin
5
+# Plugin version
6
+version: '1.0.0'
7
+# Description
8
+description: Please describe your plugin here
9
+# Minimum required fuel version
10
+fuel_version: ['9.0', '10.0']
11
+# Specify license of your plugin
12
+licenses: ['Apache License Version 2.0']
13
+# Specify author or company name
14
+authors: ['Specify author or company name']
15
+# A link to the plugin's page
16
+homepage: 'https://github.com/openstack/fuel-plugins'
17
+# Specify a group which your plugin implements, possible options:
18
+# network, storage, storage::cinder, storage::glance, hypervisor,
19
+# equipment
20
+groups: []
21
+# Change `false` to `true` if the plugin can be installed in the environment
22
+# after the deployment.
23
+is_hotpluggable: false
24
+
25
+# The plugin is compatible with releases in the list
26
+releases:
27
+  - os: ubuntu
28
+    version: mitaka-9.0
29
+    mode: ['ha']
30
+    deployment_scripts_path: deployment_scripts/
31
+    repository_path: repositories/ubuntu
32
+  - os: ubuntu
33
+    version: newton-10.0
34
+    mode: ['ha']
35
+    deployment_scripts_path: deployment_scripts/
36
+    repository_path: repositories/ubuntu
37
+
38
+
39
+# Version of plugin package
40
+package_version: '5.0.0'

+ 24
- 0
examples/fuel_plugin_example_v5/network_roles.yaml View File

@@ -0,0 +1,24 @@
1
+# `network_roles.yaml` file is used to declare VIP addresses and link
2
+# them with networks and nodes.
3
+
4
+# Unique network role name
5
+- id: "fuel_plugin_example_v5_network_role"
6
+  # Role mapping to network
7
+  default_mapping: "public"
8
+  properties:
9
+    # Should be true if network role requires subnet being set
10
+    subnet: true
11
+    # Should be true if network role requires gateway being set
12
+    gateway: false
13
+    # List of VIPs to be allocated
14
+    vip:
15
+         # Unique VIP name
16
+       - name: "vip_name"
17
+         # Optional linux namespace for VIP
18
+         namespace: "haproxy"
19
+         # Optional alias so VIP can be queried via API
20
+         alias: "vip_name"
21
+         # Optional node role list to map VIP to (defaults to
22
+         # primary-controller and controller)
23
+         node_roles:
24
+           - "fuel_plugin_example_v5_role"

+ 18
- 0
examples/fuel_plugin_example_v5/nic_config.yaml View File

@@ -0,0 +1,18 @@
1
+# This file contains additional nic attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+attribute_a:
7
+  label: "NIC attribute A"
8
+  description: "Some description"
9
+  type: "text"
10
+  value: ""
11
+  restrictions:
12
+    - condition: "settings:common.libvirt_type.value != 'kvm'"
13
+      action: "hide"
14
+attribute_b:
15
+  label: "NIC attribute B"
16
+  description: "Some description"
17
+  type: "checkbox"
18
+  value: false

+ 25
- 0
examples/fuel_plugin_example_v5/node_config.yaml View File

@@ -0,0 +1,25 @@
1
+# This file contains additional node's attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+plugin_section_a:
7
+  metadata:
8
+    group: "some_new_section"
9
+    label: "Section A"
10
+    restrictions:
11
+      - condition: "settings:common.libvirt_type.value != 'kvm'"
12
+        action: "hide"
13
+  attribute_a:
14
+    label: "Node attribute A for section A"
15
+    description: "Some description"
16
+    type: "text"
17
+    value: ""
18
+    restrictions:
19
+      - condition: "false"
20
+        action: "hide"
21
+  attribute_b:
22
+    label: "Node attribute B for section A"
23
+    description: "Some description"
24
+    type: "checkbox"
25
+    value: ""

+ 6
- 0
examples/fuel_plugin_example_v5/node_roles.yaml View File

@@ -0,0 +1,6 @@
1
+fuel_plugin_example_v5:
2
+  name: "Set here the name for the role. This name will be displayed in the Fuel web UI."
3
+  description: "Write description for your role"
4
+  has_primary: false                # whether has primary role or not
5
+  public_ip_required: false         # whether requires public net or not
6
+  weight: 100                       # weight that will be used for ordering on fuel ui

+ 21
- 0
examples/fuel_plugin_example_v5/pre_build_hook View File

@@ -0,0 +1,21 @@
1
+#!/bin/bash
2
+set -eux
3
+
4
+command -v fpm >/dev/null 2>&1 || {
5
+    echo >&2 "Install 'fpm' to build this plugin. Aborting."; exit 1;
6
+}
7
+
8
+ruby -e "require 'fpm'" 2>&1 || {
9
+    echo >&2 "'Fpm' binary file is present, but gem seems to be broken! Aborting."; exit 1;
10
+}
11
+
12
+ROOT=$(dirname `readlink -f $0`)
13
+
14
+UBUNTU_REPO_PATH=$ROOT/repositories/ubuntu
15
+CENTOS_REPO_PATH=$ROOT/repositories/centos
16
+
17
+rm -f $UBUNTU_REPO_PATH/*.deb
18
+rm -f $CENTOS_REPO_PATH/*.rpm
19
+
20
+fpm -t deb -p $UBUNTU_REPO_PATH -n fuel-simple-service -v 5.0.0 -s dir $ROOT/fuel-simple-service.py=/usr/bin/fuel-simple-service.py
21
+fpm -t rpm -p $CENTOS_REPO_PATH -n fuel-simple-service -v 5.0.0 -s dir $ROOT/fuel-simple-service.py=/usr/bin/fuel-simple-service.py

+ 0
- 0
examples/fuel_plugin_example_v5/repositories/centos/.gitkeep View File


+ 0
- 0
examples/fuel_plugin_example_v5/repositories/ubuntu/.gitkeep View File


+ 6
- 0
examples/fuel_plugin_example_v5/volumes.yaml View File

@@ -0,0 +1,6 @@
1
+# Set here new volumes for your role
2
+volumes: []
3
+volumes_roles_mapping:
4
+  fuel_plugin_example_v5_role:
5
+    # Default role mapping
6
+    - {allocate_size: "min", id: "os"}

+ 1
- 0
fuel_plugin_builder/actions/__init__.py View File

@@ -19,4 +19,5 @@ from fuel_plugin_builder.actions.build import BuildPluginV1
19 19
 from fuel_plugin_builder.actions.build import BuildPluginV2
20 20
 from fuel_plugin_builder.actions.build import BuildPluginV3
21 21
 from fuel_plugin_builder.actions.build import BuildPluginV4
22
+from fuel_plugin_builder.actions.build import BuildPluginV5
22 23
 from fuel_plugin_builder.actions.build import make_builder

+ 4
- 0
fuel_plugin_builder/actions/build.py View File

@@ -269,6 +269,10 @@ class BuildPluginV4(BuildPluginV3):
269 269
     pass
270 270
 
271 271
 
272
+class BuildPluginV5(BuildPluginV4):
273
+    pass
274
+
275
+
272 276
 def make_builder(plugin_path):
273 277
     """Creates build object.
274 278
 

+ 15
- 0
fuel_plugin_builder/templates/v5/plugin_data/bond_config.yaml.mako View File

@@ -0,0 +1,15 @@
1
+# This file contains additional bond attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+attribute_a:
7
+  label: "Bond attribute A"
8
+  description: "Some description"
9
+  type: "text"
10
+  value: ""
11
+attribute_b:
12
+  label: "Bond attribute B"
13
+  description: "Some description"
14
+  type: "checkbox"
15
+  value: false

+ 38
- 0
fuel_plugin_builder/templates/v5/plugin_data/metadata.yaml.mako View File

@@ -0,0 +1,38 @@
1
+# Plugin name
2
+name: ${plugin_name}
3
+# Human-readable name for your plugin
4
+title: Title for ${plugin_name} plugin
5
+# Plugin version
6
+version: '1.0.0'
7
+# Description
8
+description: Please describe your plugin here
9
+# Required fuel version
10
+fuel_version: ['9.0', '10.0']
11
+# Specify license of your plugin
12
+licenses: ['Apache License Version 2.0']
13
+# Specify author or company name
14
+authors: ['Specify author or company name']
15
+# A link to the plugin's page
16
+homepage: 'https://github.com/stackforge/fuel-plugins'
17
+# Specify a group which your plugin implements, possible options:
18
+# network, storage, storage::cinder, storage::glance, hypervisor
19
+groups: []
20
+# Change `false` to `true` if the plugin can be installed in the environment
21
+# after the deployment.
22
+is_hotpluggable: false
23
+
24
+# The plugin is compatible with releases in the list
25
+releases:
26
+  - os: ubuntu
27
+    version: mitaka-9.0
28
+    mode: ['ha']
29
+    deployment_scripts_path: deployment_scripts/
30
+    repository_path: repositories/ubuntu
31
+  - os: ubuntu
32
+    version: newton-10.0
33
+    mode: ['ha']
34
+    deployment_scripts_path: deployment_scripts/
35
+    repository_path: repositories/ubuntu
36
+
37
+# Version of plugin package
38
+package_version: '5.0.0'

+ 15
- 0
fuel_plugin_builder/templates/v5/plugin_data/nic_config.yaml.mako View File

@@ -0,0 +1,15 @@
1
+# This file contains additional nic attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+attribute_a:
7
+  label: "NIC attribute A"
8
+  description: "Some description"
9
+  type: "text"
10
+  value: ""
11
+attribute_b:
12
+  label: "NIC attribute B"
13
+  description: "Some description"
14
+  type: "checkbox"
15
+  value: false

+ 19
- 0
fuel_plugin_builder/templates/v5/plugin_data/node_config.yaml.mako View File

@@ -0,0 +1,19 @@
1
+# This file contains additional node's attributes provided by plugin.
2
+# Please, take a look at following link for the details:
3
+# - https://blueprints.launchpad.net/fuel/+spec/nics-and-nodes-attributes-via-plugin
4
+# - https://specs.openstack.org/openstack/fuel-specs/specs/10.0/nics-and-nodes-attributes-via-plugin.html
5
+
6
+plugin_section_a:
7
+  metadata:
8
+    group: "some_new_section"
9
+    label: "Section A"
10
+  attribute_a:
11
+    label: "Node attribute A for section A"
12
+    description: "Some description"
13
+    type: "text"
14
+    value: ""
15
+  attribute_b:
16
+    label: "Node attribute B for section A"
17
+    description: "Some description"
18
+    type: "checkbox"
19
+    value: ""

+ 3
- 2
fuel_plugin_builder/tests/test_validator_v4.py View File

@@ -27,6 +27,7 @@ class TestValidatorV4(TestValidatorV3):
27 27
     __test__ = True
28 28
     validator_class = ValidatorV4
29 29
     schema_class = SchemaV4
30
+    package_version = '4.0.0'
30 31
 
31 32
     def setUp(self):
32 33
         super(TestValidatorV4, self).setUp()
@@ -34,7 +35,7 @@ class TestValidatorV4(TestValidatorV3):
34 35
             'name': 'plugin_name-12',
35 36
             'title': 'plugin_name-12',
36 37
             'version': '1.2.3',
37
-            'package_version': '4.0.0',
38
+            'package_version': self.package_version,
38 39
             'description': 'Description',
39 40
             'fuel_version': ['8.0.0'],
40 41
             'licenses': ['Apache', 'BSD'],
@@ -106,7 +107,7 @@ class TestValidatorV4(TestValidatorV3):
106 107
             'name': 'plugin_name-12',
107 108
             'title': 'plugin_name-12',
108 109
             'version': '1.2.3',
109
-            'package_version': '4.0.0',
110
+            'package_version': self.package_version,
110 111
             'description': 'Description',
111 112
             'fuel_version': ['8.0.0'],
112 113
             'licenses': ['Apache', 'BSD'],

+ 452
- 0
fuel_plugin_builder/tests/test_validator_v5.py View File

@@ -0,0 +1,452 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+#    Copyright 2016 Mirantis, Inc.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+import mock
18
+
19
+from fuel_plugin_builder import errors
20
+from fuel_plugin_builder.tests.test_validator_v4 import TestValidatorV4
21
+from fuel_plugin_builder.validators.schemas import SchemaV5
22
+from fuel_plugin_builder.validators.validator_v5 import ValidatorV5
23
+
24
+
25
+class TestValidatorV5(TestValidatorV4):
26
+
27
+    __test__ = True
28
+    validator_class = ValidatorV5
29
+    schema_class = SchemaV5
30
+    package_version = '5.0.0'
31
+
32
+    def setUp(self):
33
+        super(TestValidatorV5, self).setUp()
34
+
35
+    def test_check_schemas(self):
36
+        mocked_methods = [
37
+            'check_metadata_schema',
38
+            'check_env_config_attrs',
39
+            'check_tasks_schema',
40
+            'check_deployment_tasks_schema',
41
+            'check_network_roles_schema',
42
+            'check_node_roles_schema',
43
+            'check_volumes_schema',
44
+            'check_components_schema',
45
+            'check_node_attributes_schema'
46
+        ]
47
+        self.mock_methods(self.validator, mocked_methods)
48
+        self.mock_methods(
49
+            self.validator,
50
+            ['validate_file_by_schema', 'check_interface_attributes_schema']
51
+        )
52
+        self.validator.check_schemas()
53
+
54
+        self.assertEqual(
55
+            [mock.call(self.validator.bond_config_path),
56
+             mock.call(self.validator.nic_config_path)],
57
+            self.validator.check_interface_attributes_schema.call_args_list)
58
+        for method in mocked_methods:
59
+            getattr(self.validator, method).assert_called_once_with()
60
+
61
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
62
+    def test_check_compatibility_failed(self, utils_mock):
63
+        fuel_version_checks = (
64
+            (['8.0', '9.0', '10.0']),
65
+            (['6.1', '7.0', '8.0']),
66
+            (['6.0', '6.1', '7.0']),
67
+            (['6.1', '7.0']),
68
+        )
69
+
70
+        for fuel_version in fuel_version_checks:
71
+            mock_data = {
72
+                'fuel_version': fuel_version,
73
+                'package_version': '5.0.0'}
74
+            err_msg = 'Current plugin format 5.0.0 is not compatible with ' \
75
+                      '{0} Fuel release. Fuel version must be 9.0 or higher.' \
76
+                      ' Please remove {0} version from metadata.yaml file or' \
77
+                      ' downgrade package_version.'.format(fuel_version[0])
78
+
79
+            self.check_raised_exception(
80
+                utils_mock, mock_data,
81
+                err_msg, self.validator.check_compatibility)
82
+
83
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
84
+    def test_check_compatibility_passed(self, utils_mock):
85
+        utils_mock.parse_yaml.return_value = {
86
+            'fuel_version': ['9.0', '9.1', '9.2', '10.0'],
87
+            'package_version': '5.0.0'}
88
+        self.validator.check_compatibility()
89
+
90
+    @mock.patch('fuel_plugin_builder.validators.base.utils.exists')
91
+    def test_check_interface_attributes_schema_validation_no_file(self,
92
+                                                                  exists_mock):
93
+        mocked_methods = ['validate_schema']
94
+        self.mock_methods(self.validator, mocked_methods)
95
+        exists_mock.return_value = False
96
+        self.validator.check_interface_attributes_schema(mock.ANY)
97
+        self.assertFalse(self.validator.validate_schema.called)
98
+
99
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
100
+    def test_check_interface_attributes_schema_validation_failed(self,
101
+                                                                 utils_mock):
102
+        data_sets = [
103
+            {
104
+                '123': {
105
+                    'label': 'Attribute without type',
106
+                    'description': 'Attribute without type',
107
+                    'value': ''
108
+                }
109
+            },
110
+            {
111
+                'attribute_without_label': {
112
+                    'description': 'Attribute without label',
113
+                    'type': 'text',
114
+                    'value': 'attribute_value'
115
+                }
116
+            }, {
117
+                'attribute_without_value': {
118
+                    'label': 'Attribute without value',
119
+                    'description': 'Attribute without value',
120
+                    'type': 'text',
121
+                }
122
+            },
123
+            {
124
+                'attribute-1': {
125
+                    'description': 'Attribute with wrong label type',
126
+                    'label': 123,
127
+                    'type': 'checkbox',
128
+                }
129
+            },
130
+            {
131
+                'attribute-2': {
132
+                    'label': 'Attribute with wrong type type',
133
+                    'type': [],
134
+                }
135
+            },
136
+            {
137
+                'attribute-3': {
138
+                    'label': 'Attribute with wrong description type',
139
+                    'type': 'text',
140
+                    'description': False
141
+                }
142
+            },
143
+            {
144
+                'attribute-4': {
145
+                    'label': 'Attribute with wrong restrictions type',
146
+                    'type': 'text',
147
+                    'restrictions': {}
148
+                }
149
+            },
150
+            {
151
+                'label': 'Missed attribute name. Wrong level nesting.',
152
+                'type': 'text',
153
+                'value': ''
154
+            },
155
+            {
156
+                'extra_level': {
157
+                    'attribute_name': {
158
+                        'label': 'Attribute with extra nesting level',
159
+                        'type': 'text',
160
+                        'value': ''
161
+                    }
162
+                }
163
+            },
164
+            {
165
+                'uns@pported_letters=!n_attr_name*': {
166
+                    'label': 'Attribute with wrong name',
167
+                    'type': 'text',
168
+                    'value': ''
169
+                }
170
+            },
171
+            ['wrong interface attributes object type']
172
+        ]
173
+
174
+        for data in data_sets:
175
+            utils_mock.parse_yaml.return_value = data
176
+            self.assertRaises(errors.ValidationError,
177
+                              self.validator.check_interface_attributes_schema,
178
+                              mock.ANY)
179
+
180
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
181
+    def test_check_interface_attributes_schema_validation_passed(self,
182
+                                                                 utils_mock):
183
+        data_sets = [
184
+            {
185
+                '123': {
186
+                    'label': 'Attribute with min required fields',
187
+                    'type': 'text',
188
+                    'value': ''
189
+                }
190
+            },
191
+            {
192
+                'Attribute_1': {
193
+                    'label': 'Attribute with restrictions & complex value',
194
+                    'description': 'Some attribute description',
195
+                    'type': 'text',
196
+                    'value': {'key1': ['val_1', 'val_2']},
197
+                    'restrictions': [
198
+                        {
199
+                            'condition': 'false',
200
+                            'action': 'disable'
201
+                        }
202
+                    ]
203
+                },
204
+                'attribute-2': {
205
+                    'label': 'Attribute with additional fields',
206
+                    'type': 'number',
207
+                    'description': 'Some attribute description',
208
+                    'value': 10,
209
+                    'min': 0
210
+                },
211
+                'metadata': {
212
+                    'label': 'Some metadata'
213
+                }
214
+            }
215
+        ]
216
+
217
+        for data in data_sets:
218
+            utils_mock.parse_yaml.return_value = data
219
+            self.validator.check_interface_attributes_schema('nic_config_path')
220
+
221
+    @mock.patch('fuel_plugin_builder.validators.base.utils.exists')
222
+    def test_check_node_attributes_schema_validation_no_file(self,
223
+                                                             exists_mock):
224
+        mocked_methods = ['validate_schema']
225
+        self.mock_methods(self.validator, mocked_methods)
226
+        exists_mock.return_value = False
227
+        self.validator.check_node_attributes_schema()
228
+        self.assertFalse(self.validator.validate_schema.called)
229
+
230
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
231
+    def test_check_node_attributes_schema_validation_failed(self, utils_mock):
232
+        data_sets = [
233
+            {
234
+                'plugin_section': {
235
+                    'metadata': {
236
+                        'label': 'Some label'
237
+                    },
238
+                    '123': {
239
+                        'label': 'Attribute without type',
240
+                        'description': 'Attribute without type',
241
+                        'value': ''
242
+                    }
243
+                }
244
+            }, {
245
+                'plugin_section': {
246
+                    'metadata': {
247
+                        'label': 'Some label'
248
+                    },
249
+                    'attribute_without_label': {
250
+                        'description': 'Attribute without label',
251
+                        'type': 'text',
252
+                        'value': 'attribute_value'
253
+                    }
254
+                }
255
+            }, {
256
+                'plugin_section': {
257
+                    'metadata': {
258
+                        'label': 'Some label'
259
+                    },
260
+                    'attribute_without_value': {
261
+                        'label': 'Attribute without value',
262
+                        'description': 'Attribute without value',
263
+                        'type': 'text',
264
+                    }
265
+                }
266
+            }, {
267
+                'plugin_section': {
268
+                    'metadata': {
269
+                        'label': 'Some label'
270
+                    },
271
+                    'attribute-1': {
272
+                        'description': 'Attribute with wrong label type',
273
+                        'label': 123,
274
+                        'type': 'checkbox',
275
+                        'value': ''
276
+                    }
277
+                }
278
+            }, {
279
+                'plugin_section': {
280
+                    'metadata': {
281
+                        'label': 'Some label'
282
+                    },
283
+                    'attribute-2': {
284
+                        'label': 'Attribute with wrong type type',
285
+                        'type': [],
286
+                        'value': ''
287
+                    }
288
+                }
289
+            }, {
290
+                'plugin_section': {
291
+                    'metadata': {
292
+                        'label': 'Some label'
293
+                    },
294
+                    'attribute-3': {
295
+                        'label': 'Attribute with wrong description type',
296
+                        'type': 'text',
297
+                        'value': '',
298
+                        'description': False
299
+                    }
300
+                }
301
+            }, {
302
+                'plugin_section': {
303
+                    'metadata': {
304
+                        'label': 'Some label'
305
+                    },
306
+                    'attribute-4': {
307
+                        'label': 'Attribute with wrong restrictions type',
308
+                        'type': 'text',
309
+                        'value': '',
310
+                        'restrictions': {}
311
+                    }
312
+                }
313
+            }, {
314
+                'plugin_section': {
315
+                    'metadata': {
316
+                        'group': 'Metadata without label'
317
+                    },
318
+                    'attribute_a': {
319
+                        'label': 'Some label',
320
+                        'type': 'text',
321
+                        'value': '',
322
+                    }
323
+                }
324
+            }, {
325
+                'plugin_section': {
326
+                    'metadata': {
327
+                        'label': None,
328
+                        'group': 'Metadata with wrong label type'
329
+                    },
330
+                    'attribute_a': {
331
+                        'label': 'Some label',
332
+                        'type': 'text',
333
+                        'value': '',
334
+                    }
335
+                }
336
+            }, {
337
+                'plugin_section': {
338
+                    'metadata': {
339
+                        'label': None,
340
+                        'group': 'Metadata with wrong restriction type',
341
+                        'restrictions': 'restrictions'
342
+                    },
343
+                    'attribute_a': {
344
+                        'label': 'Some label',
345
+                        'type': 'text',
346
+                        'value': '',
347
+                    }
348
+                }
349
+            }, {
350
+                'metadata': {
351
+                    'label': 'Some label'
352
+                },
353
+                'attribute': {
354
+                    'label': 'Missed plugin section. Wrong level nesting.',
355
+                    'type': 'text',
356
+                    'value': ''
357
+                }
358
+            }, {
359
+                'extra_level': {
360
+                    'plugin_section': {
361
+                        'metadata': {
362
+                            'label': 'Some label'
363
+                        },
364
+                        'attribute-4': {
365
+                            'label': 'Attribute with extra nesting level',
366
+                            'type': 'text',
367
+                            'value': ''
368
+                        }
369
+                    }
370
+                }
371
+            }, {
372
+                'plugin_section': {
373
+                    'metadata': {
374
+                        'label': 'Some label'
375
+                    },
376
+                    'uns@pported_letters=!n_attr_name*': {
377
+                        'label': 'Attribute with wrong name',
378
+                        'type': 'text',
379
+                        'value': ''
380
+                    }
381
+                }
382
+            }, {
383
+                'uns@pported_letters=!n_section_name': {
384
+                    'metadata': {
385
+                        'label': 'Some label'
386
+                    },
387
+                    'attribute': {
388
+                        'label': 'Attribute with wrong name',
389
+                        'type': 'text',
390
+                        'value': ''
391
+                    }
392
+                }
393
+            },
394
+            ['wrong interface attributes object type']
395
+        ]
396
+
397
+        for data in data_sets:
398
+            utils_mock.parse_yaml.return_value = data
399
+            self.assertRaises(errors.ValidationError,
400
+                              self.validator.check_node_attributes_schema)
401
+
402
+    @mock.patch('fuel_plugin_builder.validators.base.utils')
403
+    def test_check_node_attributes_schema_validation_passed(self, utils_mock):
404
+        data_sets = [
405
+            {
406
+                'plugin_section': {
407
+                    'metadata': {
408
+                        'label': 'Some label'
409
+                    },
410
+                    '123': {
411
+                        'label': 'Attribute with min required fields',
412
+                        'type': 'text',
413
+                        'value': ''
414
+                    }
415
+                },
416
+                'plugin_section123': {
417
+                    'Attribute_1': {
418
+                        'label': 'Attribute with restrictions & complex value',
419
+                        'description': 'Some attribute description',
420
+                        'type': 'text',
421
+                        'value': {'key1': ['val_1', 'val_2']},
422
+                        'restrictions': [
423
+                            {
424
+                                'condition': 'false',
425
+                                'action': 'disable'
426
+                            }
427
+                        ]
428
+                    },
429
+                    'attribute-2': {
430
+                        'label': 'Attribute with additional fields',
431
+                        'type': 'number',
432
+                        'description': 'Some attribute description',
433
+                        'value': 10,
434
+                        'min': 0
435
+                    },
436
+                    'metadata': {
437
+                        'label': 'Metadata with extra field & restrictions',
438
+                        'restrictions': [
439
+                            {
440
+                                'condition': 'false',
441
+                                'action': 'disable'
442
+                            }
443
+                        ],
444
+                        'group': 'group A'
445
+                    }
446
+                }
447
+            }
448
+        ]
449
+
450
+        for data in data_sets:
451
+            utils_mock.parse_yaml.return_value = data
452
+            self.validator.check_node_attributes_schema()

+ 13
- 0
fuel_plugin_builder/tests/test_version_mapping.py View File

@@ -20,6 +20,7 @@ from fuel_plugin_builder.validators import ValidatorV1
20 20
 from fuel_plugin_builder.validators import ValidatorV2
21 21
 from fuel_plugin_builder.validators import ValidatorV3
22 22
 from fuel_plugin_builder.validators import ValidatorV4
23
+from fuel_plugin_builder.validators import ValidatorV5
23 24
 from fuel_plugin_builder.version_mapping import get_plugin_for_version
24 25
 
25 26
 
@@ -60,6 +61,18 @@ class TestVersionMapping(BaseTestCase):
60 61
                 'templates/v4/plugin_data/'])
61 62
         self.assertEqual(result['validator'], ValidatorV4)
62 63
 
64
+    def test_get_plugin_for_version_5(self):
65
+        result = get_plugin_for_version('5.0.0')
66
+        self.assertEqual(result['version'], '5.0.0')
67
+        self.assertEqual(
68
+            result['templates'],
69
+            [
70
+                'templates/base',
71
+                'templates/v3/plugin_data/',
72
+                'templates/v4/plugin_data/',
73
+                'templates/v5/plugin_data/'])
74
+        self.assertEqual(result['validator'], ValidatorV5)
75
+
63 76
     def test_get_plugin_for_version_raises_error(self):
64 77
         with self.assertRaisesRegexp(errors.WrongPackageVersionError,
65 78
                                      'Wrong package version "2999"'):

+ 1
- 0
fuel_plugin_builder/validators/__init__.py View File

@@ -19,4 +19,5 @@ from fuel_plugin_builder.validators.validator_v1 import ValidatorV1
19 19
 from fuel_plugin_builder.validators.validator_v2 import ValidatorV2
20 20
 from fuel_plugin_builder.validators.validator_v3 import ValidatorV3
21 21
 from fuel_plugin_builder.validators.validator_v4 import ValidatorV4
22
+from fuel_plugin_builder.validators.validator_v5 import ValidatorV5
22 23
 from fuel_plugin_builder.validators.base import LegacyBaseValidator

+ 1
- 0
fuel_plugin_builder/validators/schemas/__init__.py View File

@@ -20,3 +20,4 @@ from fuel_plugin_builder.validators.schemas.v1 import SchemaV1
20 20
 from fuel_plugin_builder.validators.schemas.v2 import SchemaV2
21 21
 from fuel_plugin_builder.validators.schemas.v3 import SchemaV3
22 22
 from fuel_plugin_builder.validators.schemas.v4 import SchemaV4
23
+from fuel_plugin_builder.validators.schemas.v5 import SchemaV5

+ 77
- 0
fuel_plugin_builder/validators/schemas/v5.py View File

@@ -0,0 +1,77 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+#    Copyright 2016 Mirantis, Inc.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+from fuel_plugin_builder.validators.schemas import SchemaV4
18
+
19
+
20
+class SchemaV5(SchemaV4):
21
+
22
+    @property
23
+    def package_version(self):
24
+        return {'enum': ['5.0.0']}
25
+
26
+    @property
27
+    def node_attributes_schema(self):
28
+        return {
29
+            '$schema': 'http://json-schema.org/draft-04/schema#',
30
+            'type': 'object',
31
+            'patternProperties': {
32
+                '^[0-9a-zA-Z_-]+$': {"$ref": "#/definitions/attrItem"}
33
+            },
34
+            "definitions": {
35
+                "attrItem": self.node_nic_attributes_schema
36
+            },
37
+            "additionalProperties": False
38
+        }
39
+
40
+    @property
41
+    def node_nic_attributes_schema(self):
42
+        return {
43
+            '$schema': 'http://json-schema.org/draft-04/schema#',
44
+            'type': 'object',
45
+            'properties': {
46
+                'metadata': self.node_nic_metadata_items
47
+            },
48
+            'patternProperties': {
49
+                '^(?!metadata)[0-9a-zA-Z_-]+$': self.node_nic_attribute_items
50
+            },
51
+            "additionalProperties": False
52
+        }
53
+
54
+    @property
55
+    def node_nic_attribute_items(self):
56
+        return {
57
+            'type': 'object',
58
+            'required': ['type', 'label', 'value'],
59
+            'properties': {
60
+                'label': {'type': 'string'},
61
+                'description': {'type': 'string'},
62
+                'type': {'type': 'string'},
63
+                'value': {},
64
+                'restrictions': self.restrictions
65
+            }
66
+        }
67
+
68
+    @property
69
+    def node_nic_metadata_items(self):
70
+        return {
71
+            'type': 'object',
72
+            'required': ['label'],
73
+            'properties': {
74
+                'label': {'type': 'string'},
75
+                'restrictions': self.restrictions
76
+            }
77
+        }

+ 51
- 0
fuel_plugin_builder/validators/validator_v5.py View File

@@ -0,0 +1,51 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+#    Copyright 2016 Mirantis, Inc.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+from os.path import join as join_path
18
+
19
+from fuel_plugin_builder.validators.schemas import SchemaV5
20
+from fuel_plugin_builder.validators import ValidatorV4
21
+
22
+
23
+class ValidatorV5(ValidatorV4):
24
+
25
+    schema = SchemaV5()
26
+
27
+    def __init__(self, *args, **kwargs):
28
+        super(ValidatorV5, self).__init__(*args, **kwargs)
29
+        self.bond_config_path = join_path(self.plugin_path, 'bond_config.yaml')
30
+        self.nic_config_path = join_path(self.plugin_path, 'nic_config.yaml')
31
+        self.node_config_path = join_path(self.plugin_path, 'node_config.yaml')
32
+
33
+    @property
34
+    def basic_version(self):
35
+        return '9.0'
36
+
37
+    def check_schemas(self):
38
+        super(ValidatorV5, self).check_schemas()
39
+        self.check_node_attributes_schema()
40
+        self.check_interface_attributes_schema(self.bond_config_path)
41
+        self.check_interface_attributes_schema(self.nic_config_path)
42
+
43
+    def check_node_attributes_schema(self):
44
+        self.validate_file_by_schema(self.schema.node_attributes_schema,
45
+                                     self.node_config_path,
46
+                                     allow_not_exists=True)
47
+
48
+    def check_interface_attributes_schema(self, file_path):
49
+        self.validate_file_by_schema(self.schema.node_nic_attributes_schema,
50
+                                     file_path,
51
+                                     allow_not_exists=True)

+ 10
- 2
fuel_plugin_builder/version_mapping.py View File

@@ -20,7 +20,7 @@ from fuel_plugin_builder import errors
20 20
 from fuel_plugin_builder import utils
21 21
 
22 22
 
23
-latest_version = '4.0.0'
23
+latest_version = '5.0.0'
24 24
 
25 25
 
26 26
 def get_mapping():
@@ -47,7 +47,15 @@ def get_mapping():
47 47
              'templates/v3/plugin_data/',
48 48
              'templates/v4/plugin_data/'],
49 49
          'validator': validators.ValidatorV4,
50
-         'builder': build.BuildPluginV4}]
50
+         'builder': build.BuildPluginV4},
51
+        {'version': '5.0.0',
52
+         'templates': [
53
+             'templates/base',
54
+             'templates/v3/plugin_data/',
55
+             'templates/v4/plugin_data/',
56
+             'templates/v5/plugin_data/'],
57
+         'validator': validators.ValidatorV5,
58
+         'builder': build.BuildPluginV5}]
51 59
 
52 60
 
53 61
 def get_plugin_for_version(version):

Loading…
Cancel
Save